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

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
   
   
   
   
0 2
 

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
*/




 

你可能感兴趣的:(hdu 1983 Kaitou Kid - The Phantom Thief (2) (dfs+bfs+01三维判重 好题))