POJ - 3311 - Hie with the Pie(状压DP)

【题目描述】

给你一个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);
    }
}

猜你喜欢

转载自www.cnblogs.com/ruthank/p/10646217.html