带门和钥匙的迷宫
迷宫
https://ac.nowcoder.com/acm/problem/15136
迷宫
题意:
有一个二维迷宫,需要从S点走到E点,每一步之能选择上下左右四个方向前进一格。W代表墙壁,D代表一扇门,需持有钥匙才能通过,K代表钥匙,经过该点钥匙就会自动进入你的口袋,'.'代表是空的,可以走。
问你从起点到终点最少需要几步?
思路:
因为问的是最短路的长度,所以是bfs题
但是这个题介入了钥匙和门这俩恶心的玩意就比较坑!
你不可能通过计算一次bfs就得到答案,因为bfs时每个点只能走一次,用完这个点就扔掉了,不会走回头路,这就会导致一种情况:如样例一
4 12 WWWWWWWWWWWW WE.W.S..W.KW W..D..W....W WWWWWWWWWWWW
第三个就踩到门D了,这个时候你没有钥匙,就会进不去,最后就不能到终点。而这个地方的正解是你先去K处拿到钥匙,再去开门到终点,你会发现会重复走,所以就不是一个bfs能解决的了的事!
我们知道要想到达终点分两种情况,一是不进门去走,看看能不能走到终点,另一种是走门再到终点。
而走门又分为两种情况,一是钥匙会在路上捡到,不用刻意去捡,另一种是得先多跑几步找钥匙,再去开门。总的来说,走门得分两步,先bfs从起点到钥匙处,再bfs从钥匙到门,这样得到的肯定是最小步数。
所以,综上所述,解决这个问题可以分两种情况
- 将门的位置当成墙,再用bfs去找
- 先来一步从起点到钥匙的bfs,再来一步从钥匙到门到bfs,再来一步门到终点的bfs,最后三步相加
假设我们bfs没找到最短路时返回的是无穷大,那么如果情况1返回无穷大并且情况二中至少有一个出现无穷大,就说明到不了终点,返回-1
剩下的情况就输出情况一和情况二的最小值
好看一点的AC码
#include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <vector> #include <stack> #include <queue> #include <stdlib.h> #include <sstream> #include <map> #include <set> using namespace std; #define inf 0x3f3f3f3f #define MAX 1000000 + 7 #define endl '\n' #define mod 1e9+7; typedef long long ll ; //不开longlong见祖宗! //ios::sync_with_stdio(false); //cin.tie(0); cout.tie(0); inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;} int h, w, x1, yy1, ans, key,xk, yk ,xd, yd; int dx[] = {0, 1, 0, -1}; int dy[] = {1, 0, -1, 0}; bool vis[505][505]; char tr[505][505]; struct ran{ int x, y, step; }; queue<ran>q; ran over[5];//用来记录点的位置 bool judge(int x, int y){ if(x > h || x < 1 || y > w || y < 1)return false; else if(vis[x][y])return false; else if(tr[x][y] == 'W' || tr[x][y] == 'D')return false; else return true; } int bfs(int xx, int yy){ ran now, next; now.x = xx;now.y = yy;now.step = 0; q.push(now); vis[xx][yy] = 1; while (!q.empty()) { now = q.front();q.pop(); //一定要把结束的情况放在外面判断鸭,我之前做了一个判能否走出迷宫的题把这个放在for外面wa了,放里面ac了,所以我写的时候就放里面了,结果wa了,呜呜,写了好长时间呢,后来换了个方法写(也就是这个代码),发现和第一遍一样还是每个步数有的差1有的不差1 ,就发现原来是这个地方出了问题!淦 if(now.x == x1 && now.y == yy1){ return now.step; } for(int i = 0; i < 4; ++i){ next.x = now.x + dx[i];next.y = now.y + dy[i]; if(!judge(next.x, next.y))continue; //cout<<now.x<<' '<<now.y<<" -> "<<next.x<<' '<<next.y<<endl; vis[next.x][next.y] = 1; next.step = now.step + 1; q.push(next); } } return inf; } void init(){//初始化 memset(vis, 0, sizeof(vis)); while (!q.empty()) { q.pop(); } } int main(){ cin>>h>>w; for(int i = 1; i <= h; ++i) for(int j = 1; j <= w; ++j){ scanf(" %c",&tr[i][j]); if(tr[i][j] == 'S'){//起点 over[1].x = i;over[1].y = j; } if(tr[i][j] == 'K'){//钥匙 over[2].x = i;over[2].y = j; } if(tr[i][j] == 'D'){//门 over[3].x = i;over[3].y = j; } if(tr[i][j] == 'E'){//终点 over[4].x = i;over[4].y = j; } } init();//从起点到终点 x1 = over[4].x;yy1 = over[4].y; int a = bfs(over[1].x, over[1].y); init();//从起点到钥匙 x1 = over[2].x;yy1 = over[2].y; int b = bfs(over[1].x, over[1].y); init();//从钥匙到门 x1 = over[3].x;yy1 = over[3].y; tr[over[3].x][over[3].y] = '.';//注意要及时把门给拆了! int c = bfs(over[2].x, over[2].y); init();//从门到终点 x1 = over[4].x; yy1 = over[4].y; int d = bfs(over[3].x, over[3].y); if(a == inf && (b == inf || c == inf || d == inf)) cout<<-1<<endl; else cout<<min(a, b + c + d)<<endl; return 0; } /* 5 5 WWWWW WS.KW WW.WW WD.EW WWWWW */
在贴一份我第一遍写的奇丑无比的代码(╥﹏╥)
虽然丑了点,但是在我顿悟后改了一下,也ac了W(''0'')W
#include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <vector> #include <stack> #include <queue> #include <stdlib.h> #include <sstream> #include <map> #include <set> using namespace std; #define inf 0x3f3f3f3f #define MAX 1000000 + 7 #define endl '\n' #define mod 1e9+7; typedef long long ll ; //不开longlong见祖宗! //ios::sync_with_stdio(false); //cin.tie(0); cout.tie(0); inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;} int h, w, x1, yy1, ans, key,xk, yk ,xd, yd; int dx[] = {0, 1, 0, -1}; int dy[] = {1, 0, -1, 0}; bool vis[505][505]; char tr[505][505]; struct ran{ int x, y, step; }; queue<ran>q; bool judge(int x, int y){ if(x > h || x < 1 || y > w || y < 1)return false; else if(vis[x][y])return false; else if(tr[x][y] == 'W')return false; //else if(tr[x][y] == 'D' && key == 0)return false; else return true; } int bfs1(){//不走门直接走 ran now, next; now.x = x1;now.y = yy1;now.step = 0; vis[x1][yy1] = 1; q.push(now); while (!q.empty()) { now = q.front();q.pop(); if(tr[now.x][now.y] == 'E'){ ans = now.step; return ans; //cout<<"到此为止!\n"; } for(int i = 0; i < 4; ++i){ next.x = now.x + dx[i];next.y = now.y + dy[i]; if(!judge(next.x, next.y))continue; if(tr[next.x][next.y] == 'D')continue; //if(tr[next.x][next.y] == 'K')key = 1; //cout<<now.x<<' '<<now.y<<" -> "<<next.x<<' '<<next.y<<endl; vis[next.x][next.y] = 1; next.step = now.step + 1; q.push(next); } } return inf; } int bfs2(){//从起点去拿钥匙的距离 while (!q.empty()) { q.pop(); } memset(vis, 0, sizeof(vis)); ran now, next; now.x = x1; now.y = yy1; now.step = 0; vis[x1][yy1] = 1; q.push(now); while (!q.empty()) { now = q.front();q.pop(); if(tr[now.x][now.y] == 'K'){ ans = now.step; return ans; } for(int i = 0; i < 4; ++i){ next.x = now.x + dx[i]; next.y = now.y + dy[i]; if(!judge(next.x, next.y))continue; if(tr[next.x][next.y] == 'D')continue; // if(tr[next.x][next.y] == 'K')key = 1; next.step = now.step + 1; vis[next.x][next.y] = 1; q.push(next); } } return inf; } int bfs3(){//从钥匙到门 while (!q.empty()) { q.pop(); } memset(vis, 0, sizeof(vis)); ran now, next; now.x = xk; now.y = yk; now.step = 0; vis[xk][yk] = 1; q.push(now); while (!q.empty()) { now = q.front();q.pop(); if(tr[now.x][now.y] == 'D'){ ans = now.step; //cout<<"到此为止!\n"; return ans; } for(int i = 0; i < 4; ++i){ next.x = now.x + dx[i]; next.y = now.y + dy[i]; if(!judge(next.x, next.y))continue; //if(tr[next.x][next.y] == 'D')continue; // if(tr[next.x][next.y] == 'K')key = 1; //cout<<now.x<<' '<<now.y<<" -> "<<next.x<<' '<<next.y<<endl; next.step = now.step + 1; vis[next.x][next.y] = 1; q.push(next); } } return inf; } int bfs4(){//从门到终点 while (!q.empty()) { q.pop(); } memset(vis, 0, sizeof(vis)); ran now, next; now.x = xd; now.y = yd; now.step = 0; vis[xd][yd] = 1; q.push(now); while (!q.empty()) { now = q.front();q.pop(); if(tr[now.x][now.y] == 'E'){ ans = now.step; return ans; } for(int i = 0; i < 4; ++i){ next.x = now.x + dx[i]; next.y = now.y + dy[i]; if(!judge(next.x, next.y))continue; //if(tr[next.x][next.y] == 'D')continue; // if(tr[next.x][next.y] == 'K')key = 1; next.step = now.step + 1; vis[next.x][next.y] = 1; q.push(next); } } return inf; } int main(){ cin>>h>>w; for(int i = 1; i <= h; ++i) for(int j = 1; j <= w; ++j){ scanf(" %c",&tr[i][j]); if(tr[i][j] == 'S'){ x1 = i;yy1 = j; tr[i][j] = '.'; } if(tr[i][j] == 'K'){ xk = i;yk = j; } if(tr[i][j] == 'D'){ xd = i;yd = j; } } //bfs3(); int a = bfs1(); int b = bfs2(); int c = bfs3(); int d = bfs4(); //cout<<a<<' '<<b<<' '<<c<<' '<<d<<endl; if(a == inf && (b == inf || c == inf || d == inf)) cout<<-1<<endl; else cout<<min(a,b + c + d)<<endl; return 0; } /* 5 5 WWWWW WS.KW WW.WW WD.EW WWWWW */