Kaitou Kid - The Phantom Thief (2)
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 853 Accepted Submission(s): 293
Problem Description
破解字迷之后,你得知Kid将会在展览开始后T分钟内盗取至少一颗宝石,并离开展馆。整个展馆呈矩形分布,划分为N*M个区域,有唯一的入口和出口(不能从出口进入,同样不能从入口出去)。由某个区域可直接移动至相邻四个区域中的一个,且最快需要一分钟。假设Kid进入放有宝石的区域即可盗取宝石,无需耗时。问至少要封锁几个区域(可以封锁放有宝石的区域,但不能封锁入口和出口)才能保证Kid无法完成任务。
Input
输入的第一行有一个整数C,代表有C组测试数据。每组测试数据的第一行有三个整数N,M,T(2<=N,M<=8,T>0)。接下来N行M列为展馆布置图,其中包括:
'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
Author
LL
Source
2008杭电集训队选拔赛
解题思路:
封锁出口或者入口周围的格子.最多需要4个封锁点.
ps:因为题目有说“不能从出口进入,同样不能从入口出去”,所以我贴的一组数据答案应该为3,而不是4或者6。网上很多代码都是错的。。。
1.寻找一条盗贼的可行路线,如果没有,则ans=0.
2.如果有,对
1中的盗贼线路中的每个点dfs(依次封锁),然后再回到1.
判重的话要用三维,第三维表示是否能偷到珠宝。开始我用的第三维表示方向,WA了,这样不行,有疑问的可以看看我贴的第二组数据。
代码:
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define maxn 15
using namespace std;
int n,m,t,ans;
int sx,sy,ex,ey;
char mp[maxn][maxn];
char s[maxn];
bool vis[maxn][maxn][2]; // 三维判重 第三维-是否偷到珠宝
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
struct Node
{
int x,y;
int step,cnt;
int pathx[65],pathy[65]; // 记录路径
};
queue<Node>q;
void dfs(int depth)
{
if(depth>=ans) return ; // 剪枝
char c;
int i,j,flag=0;
int nx,ny,nstep,ncnt,tx,ty;
Node cur,now; // 这里不能用全局变量
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
cur.x=sx;
cur.y=sy;
cur.cnt=0;
cur.step=0;
vis[sx][sy][0]=1;
q.push(cur);
while(!q.empty())
{
now=q.front();
q.pop();
nx=now.x;
ny=now.y;
nstep=now.step;
ncnt=now.cnt;
if(nstep>t) break ;
if(nx==ex&&ny==ey&&ncnt) // 到达终点且偷到珠宝
{
flag=1;
break ;
}
else if(nx==ex&&ny==ey) continue ;
cur=now;
for(i=0;i<4;i++)
{
tx=nx+dx[i];
ty=ny+dy[i];
cur.cnt=ncnt;
if(mp[tx][ty]=='J') cur.cnt=1;
if(mp[tx][ty]!='#'&&!vis[tx][ty][cur.cnt])
{
vis[tx][ty][cur.cnt]=1;
cur.x=tx;
cur.y=ty;
cur.step=nstep+1;
cur.pathx[cur.step]=tx;
cur.pathy[cur.step]=ty;
q.push(cur);
}
}
}
if(!flag) // 如果能阻止盗贼偷到珠宝
{
if(ans>depth) ans=depth; // 更新ans
return ;
}
for(i=1;i<=nstep;i++) // 不能的话需继续封锁 在盗贼可行路径上封锁
{
c=mp[now.pathx[i]][now.pathy[i]];
if(c=='S'||c=='E') continue ;
mp[now.pathx[i]][now.pathy[i]]='#';
dfs(depth+1);
mp[now.pathx[i]][now.pathy[i]]=c; // 回溯
}
}
int main()
{
int i,j,test;
scanf("%d",&test);
while(test--)
{
scanf("%d%d%d",&n,&m,&t);
memset(mp,'#',sizeof(mp));
for(i=1;i<=n;i++)
{
scanf("%s",s);
for(j=1;j<=m;j++)
{
mp[i][j]=s[j-1];
if(s[j-1]=='S')
{
sx=i;
sy=j;
}
else if(s[j-1]=='E')
{
ex=i;
ey=j;
}
}
}
ans=4;
dfs(0); // 开始默认不需要封锁
printf("%d\n",ans);
}
return 0;
}
/*
2
4 3 100
JJJ
JSJ
JEJ
JJJ
3 3 7
S.J
.##
.E.
ans:
3
1
*/