hdu 3681 Prison Break bfs + 二分 + TSP

40 篇文章 0 订阅
本文介绍了一道经典的算法竞赛题目“Prison Break”的解决方案,该题结合了宽度优先搜索(BFS)、二分查找及旅行商问题(TSP)等算法思想。文章详细解释了解题思路,即通过BFS预处理特定点之间的距离,并使用二分法辅助解决TSP问题,最终找到最优路径。
摘要由CSDN通过智能技术生成
//	hdu 3681 Prison Break bfs + 二分 + TSP
//
//	解题思路:
//
//		因为G,Y不超过15,这样讲这些点单独记录下来,bfs求出
//	两两之间的距离.二分用判断TSP判断.所转化的问题就是在
//	F和Y的集合中,找到TSP路径的最小值即可.
//
//	感悟:
//
//		觉得这题,十分巧妙,仔细想来确实不是很难,但是不好
//	想,总的来说还是自己的水平不足吧,继续加油!!!FIGHTING!
//	!!
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#define For(x,a,b,c) for (int x = a; x <= b; x += c)
#define Ffor(x,a,b,c) for (int x = a; x >= b; x -= c)
#define cls(x,a) memset(x,a,sizeof(x))
using namespace std;
typedef long long ll;

const int MAX_N = 108;

const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;

const int dx[4] = {-1,0,1,0};
const int dy[4] = {0,1,0,-1};

int N;
int M;

char mp[20][20];
int dist[20][20];
int dp[1<<17][17];
struct Point{
	int x;
	int y;

	Point(){

	}

	Point(int x,int y):x(x),y(y){

	}

}p[20];

int cnt = 0;
int state;
int start;

void input(){
	cnt = 0;
	state = 0;
	start = 0;
	For(i,1,N,1){
		scanf("%s",mp[i]+1);
		For(j,1,M,1){
			if (mp[i][j] == 'F'){
				start = cnt;
				state |= 1 << cnt;
				p[cnt].x = i;
				p[cnt++].y = j;
			}else if (mp[i][j] == 'G'){
				p[cnt].x = i;
				p[cnt++].y = j;
			}else if (mp[i][j] == 'Y'){
				p[cnt].x = i;
				p[cnt].y = j;
				state |= 1 << cnt;
				cnt++;
			}
		}
	}
}

int bfs(int s,int t){
	Point st = p[s];
	Point ed = p[t];
	int ti[20][20];
	cls(ti,-1);
	queue<Point> que;
	que.push(st);
	ti[st.x][st.y] = 0;
	while(!que.empty()){
		Point u = que.front();
		que.pop();
		if (u.x == ed.x && u.y == ed.y){
			return ti[u.x][u.y];
		}

		For(i,0,3,1){
			int tx = u.x + dx[i];
			int ty = u.y + dy[i];

			if (tx < 1 || tx > N || ty < 1 || ty > M)
				continue;

			if (mp[tx][ty] == 'D')
				continue;

			if (ti[tx][ty] != -1)
				continue;
			ti[tx][ty] = ti[u.x][u.y] + 1;
			que.push(Point(tx,ty));
		}
	}
	return INF;
}

void getdist(){
	For(i,0,cnt-1,1){
		For(j,0,cnt-1,1){
			dist[i][j] = bfs(i,j);
		}
	}
}

void print(){
	For(i,0,cnt-1,1){
		For(j,0,cnt-1,1){
			printf("%d ",dist[i][j]);
		}
		puts("");
	}
}

bool ok(int x){
	cls(dp,-1);
	dp[1<<start][start] = x;

	For(i,0,(1<<cnt)-1,1){
		For(u,0,cnt-1,1){

			if (dp[i][u] == -1)
				continue;

			if (i & (1 << u) == 0) 
				continue;

			if ((i & (state)) == state)
				if (dp[i][u]!=-1)
					return true;

			For(v,0,cnt-1,1){
				if (u == v)
					continue;

				if (dist[u][v] == INF)
					continue;

				if (i & (1<< v))
					continue;

				int tmp = dp[i][u] - dist[u][v];

				if (tmp < 0)
					continue;

				dp[i | (1<< v)][v] = max(dp[i | (1<< v)][v],tmp);
				if (mp[p[v].x][p[v].y] == 'G')
					dp[i | (1 << v)][v] = x;

			}
		}
	}

	return false;

}

void solve(){
	getdist();

	int L = 1,R = 400;
	int flag = 0;
	while(L+1<=R){
		int MID = (L + R) >> 1;
		if (ok(MID)){
			flag = 1;
			R = MID;
		}else {
			L = MID + 1;
		}
	}
	if (!flag)
		puts("-1");
	else 
		printf("%d\n",L);

	//print();
}

int main(){
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	while(scanf("%d%d",&N,&M)!=EOF){
		if (N == 0 && M == 0)
			break;
		input();
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值