• 围豆豆,题解


    题目直接点链接

    题意:

      走一条从起点回到起点的路径,使得围住的豆豆的权值之和减去步数最大。(封闭叫围住)

    分析:

      围住的概念还是看看原题,上面有图,挺好理解的。然后就是处理了,这题的数据范围很小,可枚举的东西很多,我们可以分别试一试,首先先想一想,路线可以如何枚举,路线都枚举一边这个好像不是很好操作,而且路线也稍微有点多,我们要想一个别的办法,其实10*10还是比较小的数据的,还是可以考虑暴力一点的遍历,但是操作要方便一些,于是我们可以比较简单的想到Bfs,可是怎么Bfs呢?毕竟一个点可能不止到一次,不能说到过某个点就不再去了,而且不加限制又会不停的Bfs下去,跳不出循环。所有我们要考虑一种更加可靠的办法限制。

      怎么加这个限制呢?我们比较好想到的是走过相同的格子到同一个格子的continue掉,首先格子数:10*10,要开一个2的100次方的数组,不行,而且其实这个方法也不对(看看题目中的图)。那怎么办呢?看到题目中的豆豆选择方案也是可以枚举的,所有我们考虑枚举,但是怎么枚举呢?我们要定义一个和豆豆是不是在圈子里的状态,所有我们要找到一种状态可以确定/影响豆豆是不是在圈子里,我们只要考虑在最后时(即回到起点时)会怎样?先想比较好判断的,比较一般的情况,这个点如果右边(当然上下左右都可以)有奇数根线线,那么就会被包在圈子里。这是为什么呢,可以画一画图想一想(其实挺简单的,假如这个点从右边走到这里,如果右边有1根线,即点进入了图形,有两个就是进入又出去,有三个就是进去出去进去,所以有奇数个时,点在里面,有偶数个时,点不在里面)。这个貌似挺好的,但是处理的时候要注意,我们的空间是不连续的,或者说我们不能直接找右边的走过的格子数,因为会出现一条很长的横向边,如图,其中#表示边,1表示豆豆。

                            

    明明是类似的在圈子里的情况,可是判断一个在圈子里,一个不在。

    那么怎么解决这个问题呢?

    其实,遇到这种情况我们可以直接把一堆连续的看作一个就好了,当然如果上去就看作没有,但是怎么看呢,因为我们要进行Bfs,不太好判断是怎么来的,所有我们就这样,如果这个点在一串最下面,那么忽略掉(当然只有一竖直着只有一个连续的点也是最下面)。然后再对比着图看看。

    好的,现在我们知道了什么会影响到豆豆是不是在圈子里,然后就是怎么去限制Bfs,其实还是很简单的,我们找一个vis数组,如果vis[i][j][k]==1(其中i,j表示坐标,k表示状态),就不再去Bfs了。那这个k怎么定义呢,根据刚刚的叙述,你会发现如果每个豆子右边的边数奇偶都一样时,到达过一边就不要再去了,这个应该没有什么问题。那么我们只需让k的第i(二进制)位表示第i个豆子的右边的边的奇偶,说到这里,应该就没什么问题了吧,当然,我们还要枚举起点,算算复杂度,还是可以接受的,所有这一题就解决了。

    然后细节见代码。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    struct Node{//Bfs需要
        int x;
        int y;
        int s;
        int bs;//到次Node走的步数
        Node(){
        }
        Node(int a,int b,int c,int d){
            x=a;
            y=b;
            s=c;
            bs=d;
        }
    };
    queue<Node> qu;
    bool vis[15][15][(1<<9)+10];
    int Min[(1<<9)+10];//记录走到状态i所需最少步数
    int d[15][15];//记录可不可以走
    int vald[15];
    int yh[15][15];//确定某点影响的豆子
    int dx[4]={-1,1,0,0};//Bfs用
    int dy[4]={0,0,1,-1};
    int n,m;
    void Solve(int xx,int yy){
        memset(vis,0,sizeof(vis));
        qu.push(Node(xx,yy,0,0));
        vis[xx][yy][0]=1;
        while(!qu.empty()){
            Node js=qu.front();
            qu.pop();
            for(int i=0;i<4;i++){
                int x=js.x+dx[i],y=js.y+dy[i],s=js.s,bs=js.bs+1;
                if(i==0)//向上走
                    s^=yh[x][y];
                if(i==1)//向下走
                    s^=yh[js.x][js.y];
                if(x>0&&y>0&&x<=n&&y<=m&&d[x][y]==0&&vis[x][y][s]==0){
                    qu.push(Node(x,y,s,bs));
                    vis[x][y][s]=1;
                    if(x==xx&&y==yy)
                        Min[s]=min(Min[s],bs);
                }
            }
        }
    }
    int F(int a){//找到状态a的豆子权值之和
        int ans=0;
        int i=1;
        while(a){
            if(a&1)
                ans+=vald[i];
            i++;
            a>>=1;
        }
        return ans;
    }
    int main(){
        memset(Min,0x3f,sizeof(Min));
        int ds;
        scanf("%d%d%d",&n,&m,&ds);
        for(int i=1;i<=ds;i++)
            scanf("%d",&vald[i]);
        char js; 
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                scanf(" %c",&js);
                if(js=='#')
                    d[i][j]=-1;
                else{
                    d[i][j]=js-'0';
                    if(d[i][j])
                        for(int k=j+1;k<=m;k++)
                            yh[i][k]|=(1<<(d[i][j]-1));
                }
            }
        for(int i=1;i<=n;i++)//枚举起点
            for(int j=1;j<=m;j++)
                Solve(i,j);
        int ans=0;
        for(int i=0;i<=(1<<9)-1;i++)
            ans=max(ans,F(i)-Min[i]);
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    linux指令大全
    strcpy.strcmp.strlen.strcat函数的实现
    推箱子
    头文件string.h里的函数
    SVN 版本控制工具
    Nodejs 学习
    JavaScript基础知识复习
    CSS3 学习小结
    JSP中 JSTL
    JSP中的EL语言
  • 原文地址:https://www.cnblogs.com/wish-all-ac/p/12697156.html
Copyright © 2020-2023  润新知