Description
破解字迷之后,你得知Kid将会在展览开始后T分钟内盗取至少一颗宝石,并离开展馆。整个展馆呈矩形分布,划分为N*M个区域,有唯一的入口和出口(不能从出口进入,同样不能从入口出去)。由某个区域可直接移动至相邻四个区域中的一个,且最快需要一分钟。假设Kid进入放有宝石的区域即可盗取宝石,无需耗时。问至少要封锁几个区域(可以封锁放有宝石的区域,但不能封锁入口和出口)才能保证Kid无法完成任务。
Input
输入的第一行有一个整数C,代表有C组测试数据。每组测试数据的第一行有三个整数N,M,T(2<=N,M<=8,T>0)。接下来N行M列为展馆布置图,其中包括:
'S':入口
'E':出口
'J':放有宝石的区域,至少出现一次
'.':空白区域
'#':墙
'S':入口
'E':出口
'J':放有宝石的区域,至少出现一次
'.':空白区域
'#':墙
Output
对每组测试数据,输出至少要封锁的区域数。
Sample Input
2
5 5 5
SJJJJ
..##J
.JJJJ
.J...
EJ...
5 5 6
SJJJJ
..##J
.JJJJ
.J... EJ...
Sample Output
0
2
这题既要用dfs,有要用bfs。dfs搜索要封锁的区域个数,bfs搜索Kid能否盗取宝石。很容易知道封锁的区域最多有4个,因为给入口或者出口围住最多只要4个区域,那么就可以给最大值设成4,然后去搜。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
struct p
{
int x,y,t,su;
int s1[90],s2[90];
};
int n,m,sx,sy,ans,time;
char map[10][10];
int v[10][10][2];
int yi[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
void dfs(int k)
{
queue<p>q;
p f,r;
int vis=-1,i,j;
if (k>ans) return ;
f.x=sx;
f.y=sy;
f.t=0;
f.su=0;
memset(v,0,sizeof(v));
while (!q.empty()) q.pop();
v[sx][sy][0]=1;
q.push(f);
while (!q.empty())
{
r=q.front();
q.pop();
if (r.t>time) continue;
if (map[r.x][r.y]=='E'&&r.su) {vis=r.t;break;}
f.t=r.t+1;
f.su=r.su;
for (i=0;i<4;i++)
{
f.x=r.x+yi[i][0];
f.y=r.y+yi[i][1];
if (f.x>=0&&f.x<n&&f.y>=0&&f.y<m&&map[f.x][f.y]!='#')
{
if (map[f.x][f.y]=='J') f.su=1;
else f.su=r.su;
if (v[f.x][f.y][f.su]) continue;
v[f.x][f.y][f.su]=1;
for (j=1;j<=r.t;j++)
{
f.s1[j]=r.s1[j];
f.s2[j]=r.s2[j];
}
f.s1[f.t]=f.x;
f.s2[f.t]=f.y;
q.push(f);
}
}
}
if (vis==-1)
{
if (ans>k) ans=k;
return ;
}
for (i=1;i<=r.t;i++)
{
char c=map[r.s1[i]][r.s2[i]];
if (c=='S'||c=='E') continue;
map[r.s1[i]][r.s2[i]]='#';
dfs(k+1);
map[r.s1[i]][r.s2[i]]=c;
}
}
int main()
{
int c,i,j;
scanf("%d",&c);
while (c--)
{
scanf("%d%d%d",&n,&m,&time);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
scanf(" %c",&map[i][j]);
if (map[i][j]=='S') {sx=i;sy=j;}
}
ans=4;
dfs(0);
printf("%d\n",ans);
}
return 0;
}