[uva P1601] The Morning after Halloween
非常经典的一道题目,lrj的书上也有(貌似是紫书?)。
其实这题看起来就比较麻烦。。
首先要保证小鬼不能相遇,也不能互相穿过。
可以用一个vis[][][]数组来表示三个小鬼的当前处于位置是否已经访问,
dis[][][]表示到某个状态是最小步数,用short存,可以卡住空间。
但是这样效率不高。注意到每四个格子里面至少有一个‘#’,所以我们可以把原来的网格图建一个隐式图,就可以避开很多冗余判断。
为了提高效率,我用了双向bfs。
其实就是在原来bfs基础上加点东西,代码量还是有点长的。
据说我的空间还是很大,在某些oj上会被卡。。所以还需要更优秀的标记。
code:
1 %:pragma GCC optimize(2) 2 #include<bits/stdc++.h> 3 #define idx(i,j) ((i)*m+(j)) 4 #define Ms(a,x) memset(a,x,sizeof a) 5 using namespace std; 6 const int N=18,P=260,fl[5][2]={{0,1},{-1,0},{1,0},{0,-1},{0,0}}; 7 struct sta {int p[4],lays;}cur,nxt; 8 int n,m,t,G[P][5],C[P]; char ch,a[N][N]; 9 short vis[P][P][P],dis[P][P][P]; 10 queue <sta> Q[2]; 11 inline char read() { 12 ch=getchar(); 13 while (ch!=' '&&ch!='#'&&!isalpha(ch)) ch=getchar(); 14 return ch; 15 } 16 void add(int u,int v) {G[u][C[u]++]=v;} 17 bool jug(int x,int y) { 18 if (x<0||x>n-1||y<0||y>m-1) return 0; 19 return a[x][y]!='#'; 20 } 21 int update(int id) { 22 if (vis[nxt.p[0]][nxt.p[1]][nxt.p[2]]==-1) { 23 vis[nxt.p[0]][nxt.p[1]][nxt.p[2]]=id; 24 dis[nxt.p[0]][nxt.p[1]][nxt.p[2]]=nxt.lays; 25 Q[id].push(nxt); 26 return -1; 27 }else if (vis[nxt.p[0]][nxt.p[1]][nxt.p[2]]==1-id) 28 return nxt.lays+dis[nxt.p[0]][nxt.p[1]][nxt.p[2]]; 29 return -1; 30 } 31 int bfs(int id,int s) { 32 while (!Q[id].empty()) { 33 cur=Q[id].front(); 34 if (cur.lays!=s) return -1; 35 Q[id].pop(); 36 if (t==1) { 37 nxt=cur,nxt.lays=s+1; 38 for (int i=0,s1=C[cur.p[0]]; i<s1; i++) { 39 nxt.p[0]=G[cur.p[0]][i]; 40 int re=update(id); 41 if (~re) return re; 42 } 43 }else 44 if (t==2) { 45 nxt=cur,nxt.lays=s+1; 46 for (int i=0,s1=C[cur.p[0]]; i<s1; i++) { 47 nxt.p[0]=G[cur.p[0]][i]; 48 for (int j=0,s2=C[cur.p[1]]; j<s2; j++) { 49 nxt.p[1]=G[cur.p[1]][j]; 50 if (nxt.p[1]==nxt.p[0]) continue; 51 if (nxt.p[0]==cur.p[1]&&nxt.p[1]==cur.p[0]) continue; 52 int re=update(id); 53 if (~re) return re; 54 } 55 } 56 }else 57 if (t==3) { 58 nxt=cur,nxt.lays=s+1; 59 for (int i=0,s1=C[cur.p[0]]; i<s1; i++) { 60 nxt.p[0]=G[cur.p[0]][i]; 61 for (int j=0,s2=C[cur.p[1]]; j<s2; j++) { 62 nxt.p[1]=G[cur.p[1]][j]; 63 if (nxt.p[1]==nxt.p[0]) continue; 64 if (nxt.p[0]==cur.p[1]&&nxt.p[1]==cur.p[0]) continue; 65 for (int k=0,s3=C[cur.p[2]]; k<s3; k++) { 66 nxt.p[2]=G[cur.p[2]][k]; 67 if (nxt.p[0]==nxt.p[2]||nxt.p[1]==nxt.p[2]) continue; 68 if (nxt.p[0]==cur.p[2]&&nxt.p[2]==cur.p[0]) continue; 69 if (nxt.p[1]==cur.p[2]&&nxt.p[2]==cur.p[1]) continue; 70 int re=update(id); 71 if (~re) return re; 72 } 73 } 74 } 75 } 76 } 77 return -1; 78 } 79 int double_bfs() { 80 while (!Q[0].empty()) Q[0].pop(); 81 while (!Q[1].empty()) Q[1].pop(); 82 Ms(vis,-1),Ms(dis,63); 83 for (int i=0; i<3; i++) cur.p[i]=256; cur.lays=0; 84 for (int i=0; i<n; i++) 85 for (int j=0; j<m; j++) 86 if (isupper(a[i][j])) cur.p[a[i][j]-'A']=idx(i,j); 87 Q[0].push(cur),vis[cur.p[0]][cur.p[1]][cur.p[2]]=0; 88 for (int i=0; i<3; i++) cur.p[i]=256; cur.lays=0; 89 for (int i=0; i<n; i++) 90 for (int j=0; j<m; j++) 91 if (islower(a[i][j])) cur.p[a[i][j]-'a']=idx(i,j); 92 Q[1].push(cur),vis[cur.p[0]][cur.p[1]][cur.p[2]]=1; 93 for (int st=0; !Q[0].empty()&&!Q[1].empty(); st++) { 94 int tag0=bfs(0,st),tag1=bfs(1,st); 95 if (~tag0) return tag0; 96 if (~tag1) return tag1; 97 } 98 return 233666; 99 } 100 int main() { 101 while (scanf("%d%d%d",&m,&n,&t)!=EOF,n|m|t) { 102 for (int i=0; i<n; i++) 103 for (int j=0; j<m; j++) 104 a[i][j]=read(),C[idx(i,j)]=0; 105 for (int i=0; i<n; i++) 106 for (int j=0; j<m; j++) 107 for (int k=0; k<5; k++) { 108 if (!jug(i+fl[k][0],j+fl[k][1])) continue; 109 add(idx(i,j),idx(i+fl[k][0],j+fl[k][1])); 110 } 111 printf("%d\n",double_bfs()); 112 } 113 return 0; 114 }
本文详细解析了UVA P1601题目——The Morning after Halloween,介绍了使用双向BFS算法解决该问题的方法,通过构建隐式图避免冗余判断,实现了对三个小鬼在迷宫中移动的高效模拟。

被折叠的 条评论
为什么被折叠?



