hdu 1983 Kaitou Kid - The Phantom Thief (2)

题意: 破解字迷之后,你得知Kid将会在展览开始后T分钟内盗取至少一颗宝石,并离开展馆。整个展馆呈矩形分布,划分为N*M个区域,有唯一的入口和出口(不能从出口进入,同样不能从入口出去)。由某个区域可直接移动至相邻四个区域中的一个,且最快需要一分钟。假设Kid进入放有宝石的区域即可盗取宝石,无需耗时。问至少要封锁几个区域(可以封锁放有宝石的区域,但不能封锁入口和出口)才能保证Kid无法完成任务
题解:
封锁出口或者入口周围的格子. 
最多需要4个封锁点. 
所以我们可以采取这样的策略: 
1.寻找一条盗贼的可行路线,如果没有,返回0. 
2.计算封锁出口和入口四周需要的封锁点数量,取小的一个,假设是k,k <=4 
3.从少到多,遍历所有封锁点个数小于k的方案,验证是否是一条有效的覆盖方案
(可以通过是否阻止了1中的盗贼线路进行快速验证). 
如果有有效覆盖方案,返回这个方案的覆盖点值,否则继续. 
4.如果没有比k小的覆盖方案,返回k. 
时间复杂度: 
最多(M*N)^3次有效覆盖验证.即(8*8)^3=256k次.其中有很大一部分可以通过快速验证排除(取决于1的路径长短,所以一般1应该求出最短路径的可行路线)

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <set>
#include <list>
#include <queue>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define maxn 1<<16
#define mem(a) memset(a,0,sizeof(a))
const double eps = 1e-10;
int n,m,t,ans;
char map[10][10];
int vis[2][10][10];
int mx[4] = {0,0,1,-1};
int my[4] = {1,-1,0,0};
struct node
{
    int x,y,t,k;
    int rox[64],roy[64];
}start,end,temp,in;
void dfs(int deep)
{
    if(deep > ans)
        return;
    int minstep = -1;
    node q;
    queue <node> Q;
    Q.push(start);
    mem(vis);
    vis[0][start.x][start.y] = 1;
    while(!Q.empty())
    {
        q = Q.front();
        Q.pop();
        if(q.t > t)
            continue;
        if(q.k && map[q.x][q.y] == 'E')
        {
            minstep = q.t;
            break;
        }
        for(int i = 0; i < 4; i++)
        {
            int dx = q.x + mx[i];
            int dy = q.y + my[i];
            if(dx < 0 || dx >= n || dy < 0 || dy >= m)
                continue;
            if(map[dx][dy] == '#')
                continue;

            if(map[dx][dy] == 'J')
                in.k = 1;
            else
                in.k = q.k;
            if(vis[in.k][dx][dy])
                continue;
            vis[in.k][dx][dy] = 1;
            in.x = dx;
            in.y = dy;
            in.t = q.t + 1;
            for(int j = 1; j <= q.t; j++)
            {
                in.rox[j] = q.rox[j];
                in.roy[j] = q.roy[j];
            }
            in.rox[in.t] = dx;
            in.roy[in.t] = dy;
            Q.push(in);
        }
    }
    if(minstep == -1)
    {
        if(deep < ans)
            ans = deep;
        return;
    }
    for(int i = 1; i < q.t; i++)
    {
        char c = map[q.rox[i]][q.roy[i]];
        if(c == 'S' || c == 'E')
            continue;
        map[q.rox[i]][q.roy[i]] = '#';
        dfs(deep+1);
        map[q.rox[i]][q.roy[i]] = c;
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&t);
        for(int i = 0; i < n; i++)
            scanf("%s",map[i]);
        int i,j;
        memset(vis,false,sizeof(vis));
        for(i = 0; i < n; i++)
            for(j = 0; j < m; j++)
            {
                if(map[i][j] == 'S')
                {
                    start.x = i;
                    start.y = j;
                    start.t = 0;
                    start.k = 0;
                    break;
                }
            }
        ans = 4;
        dfs(0);
        printf("%d\n",ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值