洛谷4011 孤島營救問題(BFS)(狀態壓縮)
阿新 • • 發佈:2018-11-10
題目
1944 年,特種兵麥克接到國防部的命令,要求立即趕赴太平洋上的一個孤島,營救被敵軍俘虜的大兵瑞恩。瑞恩被關押在一個迷宮裡,迷宮地形複雜,但幸好麥克得到了迷宮的地形圖。迷宮的外形是一個長方形,其南北方向被劃分為 N 行,東西方向被劃分為 M 列,於是整個迷宮被劃分為 N×M 個單元。每一個單元的位置可用一個有序數對(單元的行號,單元的列號)來表示。南北或東西方向相鄰的 2 個單元之間可能互通,也可能有一扇鎖著的門,或者是一堵不可逾越的牆。迷宮中有一些單元存放著鑰匙,並且所有的門被分成P 類,開啟同一類的門的鑰匙相同,不同類門的鑰匙不同。
大兵瑞恩被關押在迷宮的東南角,即(N,M) 單元裡,並已經昏迷。迷宮只有一個入口,在西北角。也就是說,麥克可以直接進入 (1,1)單元。另外,麥克從一個單元移動到另一個相鄰單元的時間為 1,拿取所在單元的鑰匙的時間以及用鑰匙開門的時間可忽略不計。
試設計一個演算法,幫助麥克以最快的方式到達瑞恩所在單元,營救大兵瑞恩。
題解
BFS+狀態壓縮
S才14果斷狀壓拿了多少把鑰匙。
設vis[x][y][t]表示到(x,y)且鑰匙狀態為t時的最短時間,很顯然每個位置每個狀態只能走一次。
程式碼
#include<queue> #include<vector> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int inf=1<<30; const int maxn=12; const int dx[]={0,0,-1,1},dy[]={-1,1,0,0}; int n,m,p; vector<int> key[maxn][maxn]; int ma[maxn][maxn][maxn][maxn]; int vis[maxn][maxn][(1<<14)+10]; struct U{int x,y,t;}; queue<U> q; void bfs() { int t0=0; for(int i=0;i<key[1][1].size();i++) t0|=1<<key[1][1][i]-1; q.push((U){1,1,t0});vis[1][1][t0]=1; while(!q.empty()) { int x=q.front().x,y=q.front().y,t=q.front().t;q.pop(); for(int i=0;i<4;i++) { int nx=x+dx[i],ny=y+dy[i],nt=t; if(1>nx||nx>n || 1>ny||ny>m) continue; if(ma[x][y][nx][ny]==-1) continue; if(!ma[x][y][nx][ny] || (t>>ma[x][y][nx][ny]-1)&1)//p>>ma[x][y][nx][ny]-1 { for(int j=0;j<key[nx][ny].size();j++) nt|=1<<key[nx][ny][j]-1; if(vis[nx][ny][nt]) continue;vis[nx][ny][nt]=vis[x][y][t]+1; q.push((U){nx,ny,nt}); // printf("q: %d %d %d - %d\n",nx,ny,nt,vis[nx][ny][nt]); } } } } int main() { scanf("%d%d%d",&n,&m,&p); int K;scanf("%d",&K); for(int i=1;i<=K;i++) { int x1,y1,x2,y2,g; scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&g); if(!g) ma[x1][y1][x2][y2]=ma[x2][y2][x1][y1]=-1; else ma[x1][y1][x2][y2]=ma[x2][y2][x1][y1]=g; } int S;scanf("%d",&S); for(int i=1;i<=S;i++) { int x,y,q; scanf("%d%d%d",&x,&y,&q); key[x][y].push_back(q); } bfs(); int ans=inf; for(int i=0,imax=1<<p;i<imax;i++) ans=min(ans,!vis[n][m][i]?inf:vis[n][m][i]);//debug imax=1<<p-1 max(ans,vis[n][m][i]) if(ans!=inf) printf("%d\n",ans-1); else puts("-1"); return 0; }