HDU 1983 Kaitou Kid - The Phantom Thief (2)(DFS套BFS)

Kaitou Kid - The Phantom Thief (2)

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


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

【题意】:给出一个入口和一个出口,问能否堵住某些区域使得Kid不能在T时间内偷到宝石并走出去

【思路】:初看似乎只能暴搜,将所有的BFS一遍,不过思考之后就能发现,最多只要4个障碍物,就能将出口或者入口堵住,所以,方法就是:
封锁出口或者入口周围的格子. 
最多需要4个封锁点. 
所以我们可以采取这样的策略: 
1.寻找一条盗贼的可行路线,如果没有,返回0. 
2.计算封锁出口和入口四周需要的封锁点数量,取小的一个,假设是k,k <=4 
3.从少到多,遍历所有封锁点个数小于k的方案,验证是否是一条有效的覆盖方案
(可以通过是否阻止了1中的盗贼线路进行快速验证). 
如果有有效覆盖方案,返回这个方案的覆盖点值,否则继续. 
4.如果没有比k小的覆盖方案,返回k. 

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<cstdlib>
#include<algorithm>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#include<vector>
#define F first
#define S second
#define PI acos(-1.0)
#define E  exp(1.0)
#define INF 0xFFFFFFF
#define MAX -INF
#define len(a) (__int64)strlen(a)
#define mem0(a) (memset(a,0,sizeof(a)))
#define mem1(a) (memset(a,-1,sizeof(a)))
using namespace std;
template<class T> T gcd(T a, T b) {
	return b ? gcd(b, a % b) : a;
}
template<class T> T lcm(T a, T b) {
	return a / gcd(a, b) * b;
}
template<class T> inline T Min(T a, T b) {
	return a < b ? a : b;
}
template<class T> inline T Max(T a, T b) {
	return a > b ? a : b;
}
int n, m;
struct node {
	int x, y, step, rx[64], ry[64], num;
	//x,y表示坐标,num表示是否拿到宝石,step表示步数或者时间,rx[]和ry[]分别保存到达该点的路径
};
node cur; //起始点
char mp[10][10];
int ans;
int dx[] = { 0, 0, 1, -1 };
int dy[] = { 1, -1, 0, 0 };
int tt;
int vis[10][10][2]; //三维数组,第三维表示该点是否已拿到过宝石
queue<node> q;
void dfs(int deep) {
	if (deep > ans) //总共最多只需封锁四个区域,即入口或出口的四个方向
		return;
	while (!q.empty())
		q.pop();
	q.push(cur);
	node t;
	int sum = -1;
	mem0(vis);
	vis[cur.x][cur.y][0] = 1;
	while (!q.empty()) {
		t = q.front();
		q.pop();
		node nex;
		if (mp[t.x][t.y] == 'E' && t.num) { //能走到出口
			sum = t.step;
			break;
		}
		for (int i = 0; i < 4; i++) {
			int tx = t.x + dx[i];
			int ty = t.y + dy[i];
			if (tx >= n || tx < 0 || ty >= m || ty < 0 || mp[tx][ty] == '#'
					|| t.step >= tt)
				continue;
			if (mp[tx][ty] == 'J') {
				nex.num = 1;
			} else {
				nex.num = t.num;
			}
			if (vis[tx][ty][nex.num])
				continue;
			for (int k = 1; k <= t.step; k++) { //记录路径
				nex.rx[k] = t.rx[k];
				nex.ry[k] = t.ry[k];
			}
			vis[tx][ty][nex.num] = 1;
			nex.x = tx;
			nex.y = ty;
			nex.step = t.step + 1;
			nex.rx[nex.step] = tx;
			nex.ry[nex.step] = ty;
			q.push(nex);
		}
	}
	if (sum == -1) //sum==-1表示该封锁区域设置成功,kid无法完成任务
			{
		if (deep < ans)
			ans = deep;
		return;
	}
	for (int i = 1; i < t.step; i++) {
		char cc = mp[t.rx[i]][t.ry[i]]; //保存原先的地图
		if (cc == 'E' || cc == 'S') //入口或出口不能封锁
			continue;
		mp[t.rx[i]][t.ry[i]] = '#';
		dfs(deep + 1); //设置一个封锁区域后,继续遍历
		mp[t.rx[i]][t.ry[i]] = cc; //将地图还原
	}
}
int main() {
//	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout);
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d%d", &n, &m, &tt);
		for (int i = 0; i < n; i++) {
			scanf("%s", mp[i]);
			for (int j = 0; j < m; j++) {
				if (mp[i][j] == 'S')
					cur.x = i, cur.y = j;
			}
		}
		cur.num = 0;
		cur.step = 0;
		ans = 4;
		dfs(0);
		printf("%d\n", ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值