1. 程式人生 > >【旅行商問題TSP】【狀態壓縮dp】【記憶化dp】

【旅行商問題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));
	}
}