迷宫寻宝(一)
时间限制:1000 ms | 内存限制:65535 KB
难度:4
- 描述
-
一个叫ACM的寻宝者找到了一个藏宝图,它根据藏宝图找到了一个迷宫,这是一个很特别的迷宫,迷宫里有N个编过号的门(N<=5),它们分别被编号为A,B,C,D,E.为了找到宝藏,ACM必须打开门,但是,开门之前必须在迷宫里找到这个打开这个门所需的所有钥匙(每个门都至少有一把钥匙),例如:现在A门有三把钥匙,ACM就必须找全三把钥匙才能打开A门。现在请你编写一个程序来告诉ACM,他能不能顺利的得到宝藏。
- 输入
- 输入可能会有多组测试数据(不超过10组)。
每组测试数据的第一行包含了两个整数M,N(1<N,M<20),分别代表了迷宫的行和列。接下来的M每行有N个字符,描述了迷宫的布局。其中每个字符的含义如下:
.表示可以走的路
S:表示ACM的出发点
G表示宝藏的位置
X表示这里有墙,ACM无法进入或者穿过。
A,B,C,D,E表示这里是门,a,b,c,d,e表示对应大写字母的门上的钥匙。
注意ACM只能在迷宫里向上下左右四个方向移动。
最后,输入0 0表示输入结束。 输出 - 每行输出一个YES表示ACM能找到宝藏,输出NO表示ACM找不到宝藏。 样例输入
-
4 4 S.X. a.X. ..XG .... 3 4 S.Xa .aXB b.AG 0 0
样例输出 -
YES NO
- 输入可能会有多组测试数据(不超过10组)。
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; struct node { int x; int y; }n1,n2; int dx[4]={0,0,1,-1}; int dy[4]={1,-1,0,0}; int k[6]; int m,n; int begin_x,begin_y; char map[25][25]; bool vis[25][25]; bool judge(int x,int y) { if(x<0||x>=m||y<0||y>=n||vis[x][y]) return false; if(map[x][y]=='X') return false; if(map[x][y]>='a'&&map[x][y]<='e') k[map[x][y]-'a']--; return true; //其他的所有情况都返回true,都要加入队列 } bool bfs() { memset(vis,false,sizeof(vis)); queue<node>q; n1.x=begin_x; n1.y=begin_y; q.push(n1); vis[n1.x][n1.y]=true; //除门之外所有的点都要进行标记 while(!q.empty()) { n2=q.front(); q.pop(); if(map[n2.x][n2.y]=='G') return true; if(map[n2.x][n2.y]>='A'&&map[n2.x][n2.y]<='E') { if(k[map[n2.x][n2.y]-'A']==0) map[n2.x][n2.y]='.'; //说明钥匙已经全部找到了 else { if(q.empty()) return false; else { q.push(n2); //不进行标记,可以多次走,并且不再从此点进行搜索 continue; } } } for(int i=0;i<4;i++) { n1.x=n2.x+dx[i]; n1.y=n2.y+dy[i]; if(judge(n1.x,n1.y)) { q.push(n1); vis[n1.x][n1.y]=true; } } } return false; } int main() { while(scanf("%d%d",&m,&n)!=EOF&&m+n) { for(int i=0;i<m;i++) scanf("%s",map[i]); memset(k,0,sizeof(k)); //用来保存钥匙的数量 for(int i=0;i<m;i++) for(int j=0;j<n;j++) { if(map[i][j]=='S') { begin_x=i; begin_y=j; } if(map[i][j]>='a'&&map[i][j]<='e') k[map[i][j]-'a']++; } if(bfs()) printf("YES\n"); else printf("NO\n"); } return 0; }