[XSY 1176][状压dp]大包子环绕宝藏

我们考虑状压dp,令fi,j,k表示当前位于(i,j),k集合中的点与当前边有奇数交
而k集合外的点与当前边有偶数交的最小步数
bfs一遍可以得到
最后枚举合法的集合
时间复杂度:
O ( n m k 2 k O(nmk2^k)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
#define Maxn 22
char ch[Maxn][Maxn];
struct P{
    int x,y;
}p[10];
int cnt=0;
int w[10];
int f[Maxn][Maxn][256],Q[Maxn*Maxn*256];
int hd,tl;
int nx[4]={0,0,1,-1};
int ny[4]={1,-1,0,0};
inline int merge(int x,int y,int z){return x*Maxn*(1<<cnt)+y*(1<<cnt)+z;}
inline int getx(int num){return num/Maxn/(1<<cnt);}
inline int gety(int num){return num/(1<<cnt)%Maxn;}
inline int getz(int num){return num%(1<<cnt);}
inline bool Judge(int x,int y){
    if(x<1||x>n||y<1||y>m)return false;
    return ch[x][y]=='.';
}
int main(){
    scanf("%d%d",&n,&m);
    int sx,sy;
    for(register int i=1;i<=n;++i)scanf("%s",ch[i]+1);
    for(register int i=1;i<=n;++i)
        for(register int j=1;j<=m;++j)
            if(ch[i][j]=='S'){
                sx=i;sy=j;
                ch[i][j]='.';
            }else if(ch[i][j]>'0'&&ch[i][j]<'9'){
                p[ch[i][j]-'0'-1]=(P){i,j};
                cnt=max(cnt,ch[i][j]-'0');
                ch[i][j]='#';
            }
    int pre=cnt;
    for(register int i=0;i<cnt;++i)scanf("%d",&w[i]);
    for(register int i=1;i<=n;++i)
        for(register int j=1;j<=m;++j)
            if(ch[i][j]=='B'){
                p[cnt++]=(P){i,j};
                ch[i][j]='#';
            }
    memset(f,63,sizeof(f));
    f[sx][sy][0]=0;
    hd=tl=0;
    Q[tl++]=merge(sx,sy,0);
    while(hd<tl){
        int x=getx(Q[hd]);
        int y=gety(Q[hd]);
        int z=getz(Q[hd]);
        hd++;
        for(int i=0;i<4;++i)
            if(Judge(x+nx[i],y+ny[i])){
                int nz=z;
                if(i==0)
                    for(int j=0;j<cnt;++j)
                        if(p[j].x>x&&p[j].y==y)
                            nz^=(1<<j);
                if(i==1)
                    for(int j=0;j<cnt;++j)
                        if(p[j].x>x&&p[j].y==y-1)
                            nz^=(1<<j);
                if(f[x][y][z]+1<f[x+nx[i]][y+ny[i]][nz]){
                    f[x+nx[i]][y+ny[i]][nz]=f[x][y][z]+1;
                    Q[tl++]=merge(x+nx[i],y+ny[i],nz);
                }
            }
    }
    int Ans=0;
    for(int i=0;i<1<<cnt;++i){
        int ans=0;
        bool valid=true;
        for(int j=0;j<cnt;++j){
            int tmp=i&(1<<j);
            if(j>=pre&&tmp)valid=false;
            if(j<pre&&tmp)ans+=w[j];
        }
        if(!valid)continue;
        Ans=max(Ans,ans-f[sx][sy][i]);
    }
    printf("%d\n",Ans);
    return 0;
}/*
7 7
.......
.1###2.
.#...#.
.#.B.#.
.3...4.
..##...
......S
100
100
100
100
*/

猜你喜欢

转载自blog.csdn.net/ezoilearner/article/details/82939902