【旅行商问题TSP】【状态压缩dp】【记忆化dp】

【题意】

给定一个n个顶点组成的带权的有向图的距离矩阵d[i,j],要求从0开始结果所有点一次回到0,问所经过边的总权重的最小值为多少

【思路】

旅行商问题TSP,状态压缩dp,记忆化dp

【分析】

假设当前已经访问过的顶点集合为S,(起点0当作还未访问过的点),当前所在的顶点为v,用dp[S][v]表示从v出发访问剩余所有的点最终回到0的最小权重和。

dp[V][0]=0;

dp[S][u]=min(dp[S|{v}[v]]+a[u][v])    ( v不属于S )

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn = 11;
const int inf = 0x3f3f3f3f;
int a[maxn][maxn];
int dp[1 << maxn][maxn];//dp[i][j]表示已经经过的节点集合为i,当前位于j,从j出发访问剩余节点回到0的最小距离
int n;

int dfs(int S, int u) {
	if (dp[S][u] != -1)return dp[S][u];
	if (S == (1 << (n+1)) - 1 && u == 0) return dp[S][u] = 0;
	int res = inf;
	for (int v = 0; v <= n; v++) {
		if (!(S >>v & 1)) {
			res = min(res, dfs(S | (1 << v), v)+a[u][v]);
		}
	}
	return dp[S][u] = res;
}

int main() {
	while (~scanf("%d", &n),n) {
		for (int i = 0; i <= n; i++) {
			for (int j = 0; j <= n; j++) {
				scanf("%d", &a[i][j]);
			}
		}
		for (int k = 0; k <= n; k++) {
			for (int i = 0; i <= n; i++) {
				for (int j = 0; j <= n; j++) {
					a[i][j] = min(a[i][j], a[i][k] + a[k][j]);
				}
			}
		}
		memset(dp, -1, sizeof(dp));
		printf("%d\n", dfs(0, 0));
	}
}

循环代码

int dp[1 << maxn][maxn];//dp[i][j]表示已经经过的节点集合为i,当前位于j,从j出发访问剩余节点回到0的最小距离
int n;

//转移:dp[S][v]=min(dp[S][v],dp[S|1<<u][u]+d[v][u]);
void solve() {
	memset(dp, inf, sizeof(dp));
	dp[(1 << n ) - 1][0] = 0;
	
	for (int S = (1 << n) - 2; S >= 0; S--) {
		for (int v = 0; v <= n; v++) {
			for (int u = 0; u <= n; u++) {
				if(!(S>>u&1))
					dp[S][v] = min(dp[S][v], dp[S | (1 << u)][u] + a[v][u]);
			}
		}

	}
	printf("%d\n", dp[0][0]);
}

猜你喜欢

转载自blog.csdn.net/running_acmer/article/details/82933804