【题目描述】
给你一个n个城市的图,城市1~n标号,问从0点把所有城市都走一遍,且只走一遍,再回到0的最短路。
n <= 10.
【题目解析】
先求出任意两个城市的最短路。
然后用 dp[i][j] 表示走过的城市的状态为 i ,到达的城市为 j 的最短路。
那么对于dp[i][j] = max(dp[i][j], dp[i^(1<<(j-1))][k] + dis[k][j] )(枚举所有 k 点,用 k 点的状态和从 k 点走到 j 点的距离来更新)
边界条件是如果 i == 1<<(j-1),即这个状态只经过了 j 这个城市,此时dp[i][j] = dis[0][j]。
最后计算答案的时候不要忘了回到0点。
#include <iostream> #include <cstdio> #include <cstdlib> #include <queue> #include <algorithm> #define FOPI freopen("in.txt", "r", stdin); #define FOPO freopen("out.txt", "w", stdout); using namespace std; typedef long long LL; const int inf = 0x3f3f3f3f; const int maxn = 10 + 2; int n; int dp[1<<maxn][maxn]; int dis[maxn][maxn]; int main() { while(~scanf("%d", &n) && n) { for (int i = 0; i <= n; i++) for (int j = 0; j <= n; j++) scanf("%d", &dis[i][j]); for (int k = 0; k <= n; k++) 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 i = 0; i < (1 << n); i++) for (int j = 1; j <= n; j++) if (i == (1<<(j-1))) dp[i][j] = dis[0][j]; else dp[i][j] = inf; for (int i = 0; i < (1 << n); i++) for (int j = 1; j <= n; j++) { int s = 1 << (j-1); if (i & s) { if (i == s) continue; for (int k = 1; k <= n; k++) if (k != j && (i & (1<<(k-1)))) dp[i][j] = min(dp[i][j], dp[i^s][k] + dis[k][j]); } } int ans = inf; for (int i = 1; i <= n; i++) ans = min(ans, dp[(1<<n)-1][i] + dis[i][0]); printf("%d ", ans); } }