Poj 3311 Hie with the Pie (状压DP)

题目链接 : 点击打开链接

题意 :  0的位置是商店,1,2,3……表示城市,你需要经过所有的城市然后再回到商店,求出一个时间花费的最小值。

思路:刚开始的我只能想到一个暴力搜索的思路,从0开始dfs,然后当找到的点等于城市的个数的时候,在判断是否可以到0,然后结束。不过我没有去实现(才不是懒,是觉得可能超时QAQ)。然后去网上翻了题解,发现是一道状压DP的题。然后看来好长时间,才看明白。

其实是从暴力搜索的基础考虑的,如我们找 0 -> 1 ->2 之后会重复找很多个没找到的城市。很多都是没用的。如果我们可以把到每一个城市的最优解记录下路,然后再去找下一个城市,这样会避免找到很多多余的。

所以DP【i】【j】 表示当状态为i时,到达j城市的最小时间花费。

转移方程: DP【i】【j】 = min(DP【上一个可以到达i的状态】【j】 + dis【j】【i】,DP【i】【j】) ;

当然了,首先用最短路的算法求出一个点之间的最短路

#include<iostream>
#include<algorithm>
using namespace std;

#define INF 100000000
int dis[12][12]; // 记录点之间的最短路 
int dp[1 << 11][12]; // i状态下,到达j点的最短路。 到 
int n,ans;
int main(){
	while(cin >> n && n){
		for(int i = 0 ; i <= n ; i++)
			for(int j = 0 ; j <= n ; j ++)
				cin >> dis[i][j];
		for(int k = 0 ; k <= n ;k ++ )  // folyd求最短路 
			for(int i = 0 ; i <= n; i++)
				for(int j = 0 ; j <= n ; j++)	
					dis[i][j] = min (dis[i][j],dis[i][k]+dis[k][j]);
		for(int S = 0 ; S <= (1<<n)-1 ; S ++) // 第一层for循环是找符合条件的状态。 解释一下为什么是0 到 (1 <<n )-1,因为i位置的点表示的是i+1城市的状态。所以-1
	 
			for(int i = 1 ; i <= n ; i++){ // 第二次for循环是到达,i城市。 
				if(S & (1 << (i-1))){  //看状态S是否有没有经过i城市, 若没有,肯定没有讨论的必要 
					if(S == (1 << (i-1))) // 这个是判断是否 状态为只经过i这个城市,若经过的话,很明显这种状态的最小值就是从0点直接到i的最小值 
						dp[S][i] = dis[0][i];
					else { // 有多个城市的状态 
						dp[S][i] = INF ;  // 初始化为INF 
						for(int j = 1; j <= n ; j ++){  // 类似floyd的想法,看是否能通过一个j来使这个到达i城市的时间最小。 
							if(S & (1 << (j-1)) && j != i) // 判断 S状态下中 j 城市有没有经过,若没有经过的话不在讨论范围,因为这两者的状态没有练习。 
								dp[S][i] = min (dp[S^(1 << (i-1))][j] + dis[j][i],dp[S][i]); // 解释一下 ^运算,1 ^1 = 0,所以根据这个性质来取消对i城市的标记。 
						}
					}
				}
			}
		ans = dp[(1 << n) - 1][1] + dis[1][0];
		for(int i = 2 ; i <= n ; i++) // 从最后的结果中找出一个最小值 
			if(dp[(1 << n) - 1][i] + dis[i][0] < ans)
				ans = dp[(1 << n) - 1][i] + dis[i][0];
		cout << ans << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值