题意:要求在一张网格图上走出一条闭合路径,不得将炸弹包围进去,使围出的总价值减去路径长度最大。
/* 类似于poj3182的做法,只不过出现了多个点,那么就用状态压缩的方法记录一个集合即可。 */ #include<cstdio> #include<iostream> #include<cstring> #include<queue> using namespace std; char map[25][25],ch[25]; int n,m,sx,sy,tx,ty,nx,ny,gx[10],gy[10],val[10],w[1010],dp[25][25][1010],cnt=-1,ans; int dx[4]={-1,1,0,0}; int dy[4]={0,0,-1,1}; struct node{int x,y,k;}; bool ok(int j){ if(nx==gx[j]&&ny<gy[j]){ if(nx>tx)return true; } else if(tx==gx[j]&&ty<gy[j]){ if(tx>nx)return true; } return false; } void bfs(){ memset(dp,-1,sizeof(dp)); queue<node> q; node u;u.x=sx;u.y=sy;u.k=0;q.push(u);dp[sx][sy][0]=0; while(!q.empty()){ u=q.front();q.pop();nx=u.x;ny=u.y;int nk=u.k,tk; if(nx==sx&&ny==sy)ans=max(ans,w[nk]-dp[nx][ny][nk]); for(int i=0;i<4;i++){ tx=nx+dx[i];ty=ny+dy[i];tk=nk; if(tx<1||tx>n||ty<1||ty>m||(map[tx][ty]!='.'&&map[tx][ty]!='S'))continue; for(int j=0;j<=cnt;j++) if(ok(j))tk^=(1<<j); if(dp[tx][ty][tk]==-1){ dp[tx][ty][tk]=dp[nx][ny][nk]+1; node v;v.x=tx;v.y=ty;v.k=tk;q.push(v); } } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%s",ch); for(int j=1;j<=m;j++){ map[i][j]=ch[j-1]; if(map[i][j]=='S')sx=i,sy=j; if(map[i][j]>='1'&&map[i][j]<='8'){ int t=map[i][j]-'1';++cnt; gx[t]=i;gy[t]=j; } } } for(int i=0;i<=cnt;i++)scanf("%d",&val[i]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(map[i][j]=='B'){ ++cnt;gx[cnt]=i;gy[cnt]=j;val[cnt]=-10000; } for(int i=0;i<(1<<cnt+1);i++) for(int j=0;j<=cnt;j++) if(i&(1<<j))w[i]+=val[j]; bfs(); printf("%d",ans); return 0; }