HDU 3681 Prison Break
今天突然想做道题, 区域赛的题对于我来讲还是不简单的。。。 代码一多 写的看起来就挫了。。。
看网上说是状态压缩DP,看了下数据,Y+G小于等于15 好吧,看来确实是这样,一开始还在想难道可以用搜索?
状态压缩DP一直习惯于从通过前面的状态来更新当前状态,写的有些混乱。。。 下次试试从当前状态更新到下一个状态。。。
把所有的Y点和G点编号,求出各个点之间的距离,如果Y点某点与起点不连通,说明无解,否则有解 DP 遇到G则步数变为0,参考别人是用二分查找求解的 我也就这么做了。。。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int INF=1<<29; int as[600000]; void st() { int i, k=0; for(i=1; i<600000; i*=2) { as[i]=++k; } } struct Node { int x, y; } nod[17]; struct POS { POS() {} POS(int a,int b,int c) { x=a,y=b,now=c; } int x, y, now; } pos; int n, m, p, q, sx, sy; int dis[17][17], dp[600000][17], the[17][17], num, ll; char map[17][17]; bool ans; void init() { int i, j; memset(the,-1,sizeof(the)); p=1; for(i=0; i<n; i++) { for(j=0; j<m; j++) { if(map[i][j]=='F') sx=i, sy=j; if(map[i][j]=='Y') { nod[p].x=i, nod[p].y=j; the[i][j]=p; p++; } } } q=p; for(i=0; i<n; i++) for(j=0; j<m; j++) { if(map[i][j]=='G') { nod[q].x=i, nod[q].y=j; the[i][j]=q; q++; } } nod[0].x=sx, nod[0].y=sy; the[sx][sy]=0; for(i=0; i<q; i++) for(j=0; j<q; j++) { if(i==j) dis[i][j]=0; else dis[i][j]=INF; } } int dx[]= {1,0,-1,0}; int dy[]= {0,1,0,-1}; bool can(int x,int y) { if(x<0||x>=n||y<0||y>=m||map[x][y]=='D') return false; return true; } void bfs() { int i, j, nx, ny, x, y, now; POS tmp; bool vis[17][17]; for(i=0; i<q; i++) { memset(vis,0,sizeof(vis)); queue<POS> qq; qq.push(POS(nod[i].x,nod[i].y,0)); while(!qq.empty()) { tmp=qq.front(); qq.pop(); x=tmp.x, y=tmp.y, now=tmp.now; for(j=0; j<4; j++) { nx=x+dx[j], ny=y+dy[j]; if(can(nx,ny)&&!vis[nx][ny]) { if(the[nx][ny]!=-1) dis[i][the[nx][ny]]=now+1; vis[nx][ny]=true; qq.push(POS(nx,ny,now+1)); } } } } for(i=0; i<p; i++) for(j=0; j<p; j++) if(dis[i][j]==INF) ans=false; } bool deal(int maxt) { int i, j, k, tmp; bool f=false; for(i=0; i<num; i++) for(j=0; j<q; j++) dp[i][j]=INF; dp[0][0]=0; int ed; for(i=1; i<num; i++) { for(j=i; j>0; j-=j&(-j)) { tmp=j&(-j); ed=as[tmp]; for(k=0; k<q; k++) if(dp[i^tmp][k]+dis[k][ed]<=maxt) dp[i][ed]=min(dp[i^tmp][k]+dis[k][ed],dp[i][ed]); if(ed>=p&&dp[i][ed]!=INF) dp[i][ed]=0; if(dp[i][ed]!=INF) { for(k=0; k<p; k++) { if(dp[i][ed]+dis[ed][k]<=maxt) dp[i|(1<<(k-1))][k]=min(dp[i|(1<<(k-1))][k],dp[i][ed]+dis[ed][k]); } for(; k<q; k++) { if((1<<(k-1))&i) continue; if(dp[i][ed]+dis[ed][k]<=maxt) dp[i|(1<<(k-1))][k]=0; } } } if(i%ll==ll-1) { for(j=0; j<q; j++) if(dp[i][j]<=maxt) f=true; } } return f; } int main() { int i, j, tmp, l, r; st(); while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0) break; for(i=0; i<n; i++) scanf("%s",map[i]); init(); ans=true; bfs(); num=1<<(q-1); l=1, r=300; ll=1<<(p-1); if(ans) { while(l<r) { m=(l+r)>>1; if(deal(m)) r=m; else l=m+1; } } if(ans) printf("%d\n",r); else puts("-1"); } return 0; }