zoukankan      html  css  js  c++  java
  • 围豆豆,题解

    题目直接点链接

    题意:

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

    分析:

      围住的概念还是看看原题,上面有图,挺好理解的。然后就是处理了,这题的数据范围很小,可枚举的东西很多,我们可以分别试一试,首先先想一想,路线可以如何枚举,路线都枚举一边这个好像不是很好操作,而且路线也稍微有点多,我们要想一个别的办法,其实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;
    }
  • 相关阅读:
    AtCoder Regular Contest 093
    AtCoder Regular Contest 094
    G. Gangsters in Central City
    HGOI 20190711 题解
    HGOI20190710 题解
    HGOI 20190709 题解
    HGOI 20190708 题解
    HGOI20190707 题解
    HGOI20190706 题解
    HGOI 20190705 题解
  • 原文地址:https://www.cnblogs.com/wish-all-ac/p/12697156.html
Copyright © 2011-2022 走看看