poj Hie with the Pie(TSP,状压dp)

题目链接:http://poj.org/problem?id=3311
动态规划:https://blog.csdn.net/weixin_39778570/article/details/87014343
ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443

题目:访问所有城市回到自己城市0,一个城市可以多次访问。求最小花费
----------------------------------------------------------
由于一个城市可以多次访问,那么我么使用floyd预处理出两点之间的最短路,然后套上裸的TSP模版
下面实现了记忆化搜索和dp两种方式
dp[s][v] 表示从v出发访问剩余所有顶点,最终回到顶点0的所有花费
即dp[S][v] = min(dp[S][v], dp[S|1<<u][u]+d[v][u]); 
u未访问 
即dp[已访问s,s不含u][当前顶点v] = min(dp[已访问s,s含u][u] + dp[v][u])
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 15;
const int INF = 99999999;
int n,d[maxn][maxn];
int dp[1<<11][maxn];	
// dp[s][v] 表示从v出发访问剩余所有顶点,最终回到顶点0的所有花费 
// 记忆化搜索
// 已经访问过的节点的集合为S,当前位置为v 
int rec(int S, int v){
	if(dp[S][v]>=0){
		return dp[S][v];
	}
	// 已经访问过所有点并且回到0点 
	if(S==(1<<n)-1 && v==0){ 
		return dp[S][v]=0; 
	}
	int res = INF;
	for(int u=0; u<n; u++){
		if(!(S>>u & 1)){ // u不在集合S里面,未访问 
			// 下一步移动到顶点u
			res = min(res, rec(S|1<<u, u)+d[v][u]);
		}
	}
	return dp[S][v]=res;
} 
void DP(){
	for(int S=0; S<1<<n; S++){
		fill(dp[S],dp[S]+n,INF);
	}
	// 未访问过的点无,当前点0,访问剩余点到0的最小花费为0 
	dp[(1<<n)-1][0] = 0;//dp[已访问][当前点] 
	
	for(int S=(1<<n)-2; S>=0; S--){ // 阶段:已访问城市由多到少,即要访问的城市由少到多
		for(int v=0; v<n; v++){ // 状态:当前顶点
			// 接下来进行决策
			// 决定v下一步要走向哪个u 
			for(int u=0; u<n; u++){
				if(~((S>>u)&1)){ // 当前状态下,u未访问 
					dp[S][v] = min(dp[S][v], dp[S|1<<u][u]+d[v][u]); 
				}
			} 
		}
	} 
	printf("%d\n", dp[0][0]);
}
int main(){
	while(scanf("%d",&n)&&n){
		n++;
		for(int i=0; i<n; i++){
			for(int j=0; j<n; j++){
				cin>>d[i][j];
			}
		}
		for(int k=0; k<n; k++){
			for(int i=0; i<n; i++){
				for(int j=0; j<n; j++){
					d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
				}
			}
		}
		DP(); // 0ms
	//	memset(dp,-1,sizeof(dp));
	//	printf("%d\n", rec(0,0));	//16ms
	}

	return 0;
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页