标签:总结 bfs int res BFS vis 双向 now 步数
双向BFS
若相遇点是起始点,则步数为 s t e p n o w ∗ 2 step_{now}*2 stepnow∗2 ,因为起点和终止点拓展的步数相同
若相遇点是终止点,则步数为 s t e p n o w ∗ 2 − 1 step_{now}*2-1 stepnow∗2−1,因为起点多拓展了一步
骑士精神
本题可以用双向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.w∗2+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());
}
}
标签:总结,bfs,int,res,BFS,vis,双向,now,步数 来源: https://blog.csdn.net/cqbzlydd/article/details/116358050
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。