HDU 1983:Kaitou Kid - The Phantom Thief (2)


Kaitou Kid - The Phantom Thief (2)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1404    Accepted Submission(s): 525

点击打开链接
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


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <queue>

using namespace std;

const int MAXN = 10;
char Map[MAXN][MAXN];
int vis[MAXN][MAXN][2];
/**本来想用vis来记录的三维是横坐标,纵坐标和到达该位置时的水晶数,那么第三维就应至少
开64,但是想了想,水晶数大于1和等于1事实上等价,只要到达该位置获得过水晶就可以了。所以只用
2维来进行标记**/
int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
int C,N,M,T;
int sx,sy,ex,ey;
struct pos
{
    int x;
    int y;
    int flag;  ///用来标记到达该位置是否已经获得水晶
    int time;  ///记录时间
};
bool BFS()
{
    queue<pos>qu;
    pos now,nex;
    memset(vis,0,sizeof(vis));
    now.x = sx;
    now.y = sy;
    now.flag = 0;
    now.time = 0;
    vis[now.x][now.y][now.flag] = 1;
    qu.push(now);
    while(!qu.empty())
    {
        now = qu.front();
        qu.pop();
        if(now.time <= T)
        {
            if(now.x == ex && now.y == ey && vis[now.x][now.y][1])
                return false;
            if(now.time == T)  
                continue;
        ///时间最多为T,去考虑大于T的情况是没有什么意义的,不要花费宝贵时间去处理无用的情况
        }
        for(int i = 0; i < 4; i++)
        {
            nex.x = now.x + dir[i][0];
            nex.y = now.y + dir[i][1];
            nex.time = now.time + 1;
            ///不能越界,不能是墙
            if(nex.x<0 || nex.x>=N || nex.y<0 || nex.y>=M) continue;
            if(Map[nex.x][nex.y] == '#') continue;
            if(now.flag == 1 || Map[nex.x][nex.y] == 'J')  
            {
                ///如果前一个位置已经拿到过水晶,或这个位置上有水晶。当前flag都置为1
                nex.flag = 1;
                if(vis[nex.x][nex.y][nex.flag]==0)
                {
                    vis[nex.x][nex.y][nex.flag] = 1;
                    qu.push(nex);
                }
            }
            else
            {
                nex.flag = now.flag;
                if(vis[nex.x][nex.y][nex.flag]==0)
                {
                    vis[nex.x][nex.y][nex.flag] = 1;
                    qu.push(nex);
                }
            }

        }
    }
    return true;
}
bool dfs(int t)
{
    if(!t) return BFS();
    for(int i=0;i<N;i++)
        for(int j=0;j<M;j++)
        {
            if(Map[i][j] == 'S' || Map[i][j]=='#' || Map[i][j]=='E') continue;
            char ch = Map[i][j];
            Map[i][j]='#';
            if(dfs(t-1)) return true;
            Map[i][j] = ch;
        }
    return false;
}
int main()
{
    scanf("%d",&C);
    while(C--)
    {
        scanf("%d%d%d",&N,&M,&T);
        for(int i = 0; i < N; i++)
            for(int j = 0; j < M; j++)
            {
                scanf(" %c",&Map[i][j]);
                if(Map[i][j] == 'S')
                {
                    sx = i; sy = j;
                }
                if(Map[i][j] == 'E')
                {
                    ex = i; ey = j;
                }
            }
        if(BFS())
            printf("0\n");
        else
        {
            int flag = 1;
            for(int i = 1; i < 4; i++)
            {
                if(flag)
                {
                    if(dfs(i))
                    {
                        printf("%d\n",i);
                        flag = 0;
                    }
                }
            }
            if(flag)
                printf("4\n");
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值