题目链接:Click here~~
又是一道迷宫问题。这次,地图中多了门和钥匙这两个元素。所以,我们只要考虑如何处理这两个新增的东西就好了。
首先,在输入数据时,对于钥匙,我们可以用一个数组lock[]保存要打开这扇门需要几把钥匙,当我们遇到钥匙,就给对应的lock[]加一。
而对于门,因为必须找齐钥匙才可以开,所以当我们遇到门的时候,可以先把它存到一个栈里(每个门各自对应一个栈)。
好了数据输入完,开始从起点广搜。
如果搜到钥匙,就再用一个数组key[]保存已搜到的钥匙数量。
如果队列为空但还没有到终点的话,就找有没有可以打开的门。如果有,把门打开,重新从起点搜。如果没有,表示不能到达。
#include <queue>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
using namespace std;
typedef struct
{
int x,y;
}Ac;
queue <Ac> S,door[5];
int dir[]={0,1,0,-1,1,0,-1,0};
int from_x,from_y,to_x,to_y;
int lock[5],key[5];
int map[25][25];
bool in[25][25];
bool bfs()
{
while(!S.empty())
{
Ac R = S.front();
S.pop();
if(R.x == to_x && R.y == to_y)
return true;
for(int k=0;k<8;)
{
int x = R.x + dir[k++];
int y = R.y + dir[k++];
if(!in[x][y] && map[x][y]) //路或钥匙
{
S.push({x,y});
in[x][y]=1;
if(map[x][y]>0) //钥匙
{
key[map[x][y]-1]++;
map[x][y]=-1;
}
}
}
if(S.empty())
{
memset(in,0,sizeof(in));
int find=0;
for(int i=0;i<5;i++)
{
if(key[i] && key[i]==lock[i])//芝麻开门
{
key[i]=0,find=1;
while(!door[i].empty())
{
R = door[i].front();
int x = R.x;
int y = R.y;
map[x][y]=-1;
door[i].pop();
}
}
}
if(find)
S.push({from_x,from_y});
else
break;
}
}
return false;
}
void clear()
{
while(!S.empty())
S.pop();
for(int i=0;i<5;i++)
while(!door[i].empty())
door[i].pop();
}
int main()
{
int h,w;
while(scanf("%d%d",&h,&w),h||w)
{
getchar();
memset(lock,0,sizeof(lock));
memset(map,0,sizeof(map));
memset(key,0,sizeof(key));
memset(in,0,sizeof(in));
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
{
char c = getchar();
switch(c)
{
case 'S':from_x=i;from_y=j;S.push({i,j});break;
case 'G':to_x=i,to_y=j;
case '.':map[i][j]=-1;break;
}
if(islower(c)) //钥匙
{
lock[c-'a']++;
map[i][j] = c-'a'+1;
}
if(isupper(c) && c!='G' && c!='S' && c!='X')//门
{
door[c-'A'].push({i,j});
}
}
getchar();
}
bool yes=bfs();
if(yes)
puts("YES");
else
puts("NO");
clear();
}
return 0;
}