1. 程式人生 > >POJ - 3311 - Hie with the Pie(狀壓DP)

POJ - 3311 - Hie with the Pie(狀壓DP)

space stdout tin while type iostream scanf lse min

【題目描述】

給你一個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\n", ans); } }

POJ - 3311 - Hie with the Pie(狀壓DP)