【总结】双向BFS

双向BFS

若相遇点是起始点,则步数为 s t e p n o w ∗ 2 step_{now}*2 stepnow2 ,因为起点和终止点拓展的步数相同

若相遇点是终止点,则步数为 s t e p n o w ∗ 2 − 1 step_{now}*2-1 stepnow21,因为起点多拓展了一步

骑士精神

本题可以用双向BFS,因为 s t e p < = 15 step<=15 step<=15 ,所以总拓展数 <= 8 8 8^8 88

第一种方法是暴力枚举是否有相同的棋盘,可能超时。

第二种方法是将状态hash成一个整数。这个整数可以用 m a p map map 存。

笨笨的跳棋

定义四元组 ( x 1 , x 2 , x 3 , x 4 ) (x1,x2,x3,x4) (x1,x2,x3,x4)

考虑双向BFS,当跳到相同状态时就求到了最小步数。

考虑怎么判断是否超过步数。

注意到当取出 x x x 时,此时已走的步数为 n o w . w ∗ 2 + m p [ s ] now.w*2+mp[s] now.w2+mp[s] (当前方向已走步数+反方向已走最远步数),可以在此处剪枝。

也就是说,每个方向一次扩展一层,当一层在扩展时,另一层是不动的,当一边扩展完一层时,另一边才会扩展。

字串变换

显然用一个字符串来表示状态。

关键是怎么转移。

暴力即可。

Nightmare Ⅱ

这题用一个队列极难编写。。。

突然觉得 g m gm gm 的方法一点都不好。。。

双向BFS还是要用两个队列。。。分别模拟。。。。用一个 r e s res res 记录当前搜索到的层数。。。用二维 v i s vis vis 数组记录。。。

结构体里的东西越少越好。。。

这道题有点特殊,是bfs里套bfs。bfs外面走一层,里面只跑当前轮次。

最后一个问题:bfs里面的循环是不是一定走三步?其实这个问题可以用贪心解释。当然是走得越多越好,而bfs里面已经将走不满3步的情况算了。所以归根结底,本题还是只有一个bfs,只不过外层bfs是来限制次数的。

#include <bits/stdc++.h> #define LL long long using namespace std; int n, m, dp[810][810]; int res; int dx[4] = { -1, 0, 1, 0 }, dy[4] = { 0, 1, 0, -1 }; bool vis[810][810][2]; char a[810][810]; struct Node { //(x,y),step,dir int x, y; } st, ed, goal[5]; queue<Node> Q[2]; bool check(int x,int y) { //一个位置合法应满足:当前时间没有被鬼占领,没有障碍物,没有出界 if (x < 1 || x > n || y < 1 || y > m || a[x][y] == 'X') return 0; //当前时间t,鬼的覆盖应为2(step+1) for (int i = 0; i < 2; i++) if (abs(x - goal[i].x) + abs(y - goal[i].y) <= 2 * res) return 0; return 1; } bool bfs(int ind) { int t=Q[ind].size(); //只跑当前轮次 while(t--) { Node now=Q[ind].front(); Q[ind].pop(); if(!check(now.x,now.y)) continue; for(int i=0;i<4;i++) { int x=now.x+dx[i],y=now.y+dy[i]; if(!check(x,y)||vis[x][y][ind]) continue; if(vis[x][y][ind^1]) return 1; vis[x][y][ind]=1; Q[ind].push({x,y}); } } return 0; } int two_waybfs() { //可以停留,所以状态可以保留(已经保证了相遇点合法) while(Q[0].size()) Q[0].pop(); while(Q[1].size()) Q[1].pop(); Q[0].push(st),Q[1].push(ed); vis[st.x][st.y][0]=1; vis[ed.x][ed.y][1]=1; res=0; while (Q[0].size()&&Q[1].size()) { res++; int cou=3; while(cou--) if(bfs(0)) return res; if(bfs(1)) return res; } return -1; } int main() { int T; scanf("%d", &T); while (T--) { memset(vis,0,sizeof(vis)); scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%s", a[i] + 1); int num = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (a[i][j] == 'Z') goal[num].x = i, goal[num].y = j,num++; if (a[i][j] == 'M') st.x = i, st.y = j; if (a[i][j] == 'G') ed.x = i, ed.y = j; } // for(int i=0;i<num;i++) printf("kkk %d %d\n",goal[i].x,goal[i].y); printf("%d\n", two_waybfs()); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530343.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(63)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示