hdu4856 (bfs+状压dp)

http://acm.hdu.edu.cn/showproblem.php?pid=4856

题意:
一个 n ∗ n n*n nn的网格图中有 m m m个隧道,你可以从任意起点出发,问走过所有隧道需要的最小步数。

思路:
b f s bfs bfs预处理出任意两个点之间的最短路,然后状压dp
d p [ i ] [ j ] 表 示 当 前 走 过 的 隧 道 状 态 为 i , 最 后 走 到 的 隧 道 为 j 的 最 小 步 数 dp[i][j]表示当前走过的隧道状态为i,最后走到的隧道为j的最小步数 dp[i][j]ij
那么
d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i ( 1 < < j ) ] [ k ] + d i s ( k , j ) ) dp[i][j] = min(dp[i][j], dp[i^(1<<j)][k]+dis(k,j)) dp[i][j]=min(dp[i][j],dp[i(1<<j)][k]+dis(k,j))
其中 d i s ( j , k ) dis(j,k) dis(j,k) 表示隧道 j j j 的终点到隧道 k k k 的起点的最短路径长度。

#include<bits/stdc++.h>
using namespace std;
char mp[20][20];
int vis[20][20];
int n,m,num;
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
int dis[20][20][20][20],dp[1<<17][20];
struct node{
	int x,y,st,res;
};
struct state{
	int x1,y1,x2,y2;
}p[20];
int ba;
int bfs(int s,int e){
	queue<node>q;
	memset(vis,0,sizeof(vis));
	while(!q.empty()) q.pop();
	node a,b;
	a.x = s, a.y = e;
	dis[s][e][s][e] = 0;
	q.push(a);
	while(!q.empty()){
		b = q.front();
		q.pop();
		for(int i = 0; i < 4; i++){
			a.x = b.x + dir[i][0];
			a.y = b.y + dir[i][1];
			if(a.x <= 0 || a.x > n || a.y <= 0 || a.y > n || vis[a.x][a.y] || mp[a.x][a.y] == '#') continue;
			vis[a.x][a.y] = 1;
			dis[s][e][a.x][a.y] = min(dis[s][e][a.x][a.y],dis[s][e][b.x][b.y] + 1);
			q.push(a);
		}
	}
	return 0;
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		memset(dis,0x3f3f3f3f,sizeof(dis));
		for(int i = 1; i <= n; i++){
			scanf("%s",mp[i]+1);
		
		}
		int sz = 1<<m;
		for(int i = 0; i < m; i++){
			scanf("%d%d%d%d",&p[i].x1,&p[i].y1,&p[i].x2,&p[i].y2);
		}
		int ans = 0x3f3f3f3f;
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				if(mp[i][j] == '.'){
					bfs(i,j);
				}
			}
		}
		
		memset(dp,0x3f3f3f3f,sizeof(dp));
		for(int j = 0; j < m; j++){
			dp[1<<j][j] = 0;
		}
		for(int i = 0; i < sz; i++){
			for(int j = 0; j < m; j++){
				if(i&(1<<j)){
					for(int k = 0; k < m; k++){
						//if(j == k) continue;
						if(i&(1<<k)){
							dp[i][j] = min(dp[i][j], dp[i^(1<<j)][k] + dis[p[k].x2][p[k].y2][p[j].x1][p[j].y1]);
						}
					}
				}
			}
		}
		for(int i = 0; i < m; i++)
			ans = min(ans, dp[sz-1][i]);
		if(ans == 0x3f3f3f3f) ans = -1;
		printf("%d\n",ans);
	}
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值