hdu 1983 Kaitou Kid - The Phantom Thief (2) (dfs+bfs+01三维判重 好题)

来源:互联网 发布:顾客特殊要求矩阵 编辑:程序博客网 时间:2024/06/05 13:27

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
25 5 5SJJJJ..##J.JJJJ.J...EJ...5 5 6SJJJJ..##J.JJJJ.J...EJ...
 

Sample Output
02
 

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 15using 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;}/*24 3 100JJJJSJJEJJJJ3 3 7S.J.##.E.ans:31*/