题意:
给你一个NXM的迷宫,$代表John要偷文件,.代表空,*代表墙,大写字母X表示门,x待变一个钥匙,X门可以用x开启
其中可能有多条X门,一个x钥匙可以开多条X门
迷宫外围任意一点都可以走
2<=N,M<= 100
方法:
对迷宫的每个边缘进行dfs,然后如果存在有门未遍历且有该门的钥匙则一直dfs,直到遍历完所有能遍历的门为止,其中每个遍历过的点进行标记,不再遍历
代码:
#include <cstdio>
#include <cstring>
struct node
{
int x,y;
int flag;
}z[10005];
int zz[27];
char m[111][111];
int vis[111][111];
int ans ,tot; //tot代表门的个数
int n, mm;
int add_x[]= {1, -1, 0, 0};
int add_y[]= {0, 0, 1, -1};
void dfs(int x, int y)
{
if(m[x][y]>='A' && m[x][y]<= 'Z'&&zz[m[x][y]-'A'+1]== 0)
{
if(!vis[x][y])
{
tot++;
z[tot].x= x;
z[tot].y= y;
z[tot].flag= m[x][y]- 'A' + 1;
}
return;
}
if(!vis[x][y]&&m[x][y]>='a' && m[x][y]<= 'z')
zz[m[x][y]-'a'+1]= 1;
vis[x][y]= 1;
if(m[x][y]=='$')
ans++;
for(int i= 0; i< 4; i++)
{
int xx= x+ add_x[i];
int yy= y+ add_y[i];
if(xx>= 1 && xx<= n && yy>= 0 && yy< mm && !vis[xx][yy]&& m[xx][yy]!='*')
dfs(xx, yy);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(vis, 0, sizeof(vis));
scanf("%d %d",&n,&mm);
for(int i= 1; i<= n; i++)
scanf("%s",m[i]);
memset(zz, 0, sizeof(zz));
char ch[30];
scanf("%s",ch+1);
int len= strlen(ch+1);
if(ch[1]!= '0')
for(int i= 1; i<= len; i++)
zz[ch[i]-'a'+1]= 1;
ans= tot= 0;
for(int i= 0; i< mm; i++)
{
if(!vis[1][i]&& m[1][i]!='*')
dfs(1, i);
if(!vis[n][i] && m[n][i]!='*')
dfs(n, i);
}
for(int i= 1; i<= n; i++)
{
if(!vis[i][0]&& m[i][0]!='*')
dfs(i, 0);
if(!vis[i][mm-1] && m[i][mm-1]!='*')
dfs(i, mm-1);
}
int p= 0;
for(int i= 1; i<= tot; i++)
if(vis[z[i].x][z[i].y]== 0 && zz[z[i].flag])
{
p= 1;
break;
}
while(p)
{
p= 0;
for(int i= 1; i<= tot; i++)
if(vis[z[i].x][z[i].y]== 0 && zz[z[i].flag])
{
dfs(z[i].x, z[i].y);
}
for(int i= 1; i<= tot; i++)
if(vis[z[i].x][z[i].y]== 0 && zz[z[i].flag])
{
p= 1;
break;
}
}
printf("%d\n",ans);
}
return 0;
}