http://acm.nyist.net/JudgeOnline/problem.php?pid=82
分析:可以重复走,在找到新钥匙的时候,可以跳到门的地方(可以到达改门)判断是否可以打开门。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int NM=25;
char str[NM][NM];
int dx[NM],dy[NM],key[NM],get[NM],n,m;
bool vis[NM][NM],flag;
int d[4][2]={-1,0,1,0,0,-1,0,1};
void DFS(int x,int y){
int x1,y1,i,t;
if(flag) return;
if(str[x][y]=='G'){
flag=true;return;
}
for(i=0;i<4;i++){
x1=x+d[i][0];y1=y+d[i][1];
if(x1>=0&&x1<n && y1>=0&&y1<m && !vis[x1][y1] && str[x1][y1]!='X'){
vis[x1][y1]=1; //DFS和BFS一样,到达某点的时候,已经把该点能够产生的情况都考虑在内了,所以<strong>不用回溯</strong>
if(str[x1][y1]>='A' && str[x1][y1]<='E'){
t=str[x1][y1]-'A';
dx[t]=x1,dy[t]=y1;
if(get[t]==key[t]) DFS(x1,y1);
}
else if(str[x1][y1]>='a' && str[x1][y1]<='e'){
t=str[x1][y1]-'a';
get[t]++;
if(dx[t]!=-1) DFS(dx[t],dy[t]); //能够到达门所在的位置
else DFS(x1,y1);
}
else DFS(x1,y1);
}
}
}
int main()
{
int sx,sy,i,j;
while(scanf("%d%d",&n,&m) && (n||m)){
memset(key,0,sizeof(key));
memset(dx,-1,sizeof(dx));memset(dy,-1,sizeof(dy));
memset(get,0,sizeof(get));
for(i=0;i<n;i++){
scanf("%s",str[i]);
for(j=0;j<=m;j++){
if(str[i][j]>='a' && str[i][j]<='e')
key[str[i][j]-'a']++;
else if(str[i][j]=='S') sx=i,sy=j;
}
}
flag=false;
memset(vis,0,sizeof(vis));
vis[sx][sy]=1;
DFS(sx,sy);
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}