HDU 3085 Nightmare Ⅱ(双向BFS)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3085
题目大意:给你一张n*m地图上,上面有有
‘. ’:路
‘X':墙
’Z':鬼,每秒移动2步,可以穿墙,开始有两个,每开始时鬼先动。
‘M’:男生,每秒可走3步。
‘G’:女生,每秒可走1步。
解题思路:第一次写双向BFS,写了我好久,开始还是想着先bfs计算step[x][y][t]把每个位置被鬼占据的时间处理一下然后再用双向BFS计算两人相遇时间。后来发现因为鬼可以穿墙,可以直接用曼哈顿距离判断是否会被鬼抓到。还有,开始我都不知道每秒走三步怎么搞。。。后来看了网上的博客,知道可以通用size限制一下出队数,三次bfs实现每秒走三步。太乱了,稍微总结一下:
①两人给vis[x][y]分别标记1,2当某次bfs遇到不同标记说明两人相遇。
②用曼哈顿距离判断时间t走到某个位置是否会被鬼抓到。
③因为鬼先行动,每次t+1时,在人行动前要判断在当前位置会不会被鬼抓到。
④用size=q[mark].size()控制每次出队数,实现一秒走三步。
⑤最坑爹的一点,用scanf("%c",&map[i][j])无限超时,感觉里面绝对有不正常的数据,后来用scanf("%s",map[i]+1)每次输入一行才过掉。
代码:
1 #include<iostream> 2 #include<queue> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 const int N=805; 8 9 int n,m,t; 10 int d[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; 11 char map[N][N]; 12 int vis[N][N]; 13 14 struct node{ 15 int x,y; 16 }M,G,pre,now,a[3]; 17 queue<node>q[3]; 18 19 bool judge(int x,int y){ 20 if(x<1||y<1||x>n||y>m||map[x][y]=='X') 21 return false; 22 //利用曼哈顿距离判断是否会被鬼抓到 23 for(int i=1;i<=2;i++){ 24 if(abs(x-a[i].x)+abs(y-a[i].y)<=2*t) 25 return false; 26 } 27 return true; 28 } 29 30 bool bfs(int mark){ 31 //小技巧,利用size就可以控制出队的都是上一步的,而不会将这一步的也出队,就能实现走3步了。 32 int size=q[mark].size(); 33 while(size--){ 34 pre=q[mark].front(); 35 q[mark].pop(); 36 //鬼在人之前行动,时间每增加1,先判断鬼能不能把人吃掉 37 if(!judge(pre.x,pre.y)) 38 continue; 39 for(int i=0;i<4;i++){ 40 int xx=pre.x+d[i][0]; 41 int yy=pre.y+d[i][1]; 42 if(!judge(xx,yy)) 43 continue; 44 //遇到不同标记说明两人相遇 45 if(vis[xx][yy]){ 46 if(vis[xx][yy]!=mark) 47 return true; 48 else 49 continue; 50 } 51 vis[xx][yy]=mark; 52 now.x=xx; 53 now.y=yy; 54 q[mark].push(now); 55 } 56 } 57 return false; 58 } 59 60 int solve(){ 61 //清空队列 62 while(!q[1].empty()) q[1].pop(); 63 while(!q[2].empty()) q[2].pop(); 64 q[1].push(M); 65 q[2].push(G); 66 vis[M.x][M.y]=1,vis[G.x][G.y]=2; 67 t=0; 68 //双向bfs 69 while(!q[1].empty()||!q[2].empty()){ 70 t++; 71 for(int i=1;i<=3;i++){ 72 if(bfs(1)) 73 return t; 74 } 75 if(bfs(2)) 76 return t; 77 } 78 return -1; 79 } 80 81 int main(){ 82 int T; 83 scanf("%d",&T); 84 while(T--){ 85 memset(vis,0,sizeof(vis)); 86 scanf("%d%d",&n,&m); 87 //注意用scanf("%c",map[i][j])会超时 88 for(int i=1,cnt=0;i<=n;i++){ 89 scanf("%s",map[i]+1); 90 for(int j=1;j<=m;j++){ 91 if(map[i][j]=='M') 92 M.x=i,M.y=j; 93 if(map[i][j]=='G') 94 G.x=i,G.y=j; 95 if(map[i][j]=='Z') 96 a[++cnt].x=i,a[cnt].y=j; 97 } 98 } 99 printf("%d\n",solve()); 100 } 101 return 0; 102 }