[POJ 3311] Hie with the Pie

这是状压DP中常见的一类问题(TSP问题)(废话)

题目大意:

给你一个n+1个点的有向完全图,现在要你从0号节点出发走过1-n号点至少一次,再返回0号点的最少时间,1<=n<=10

题意分析:

由于题目给出的是有向完全图并且以邻接矩阵的形式给出,所以我们先floyd预处理出最短的路径

设状态dp [ state ] [ i ]表示从0出发,走完state中的所有的点,最后停在i点的最短距离

枚举 i 点之前的一个停留点 j ,得到如下的状态转移方程:

dp [ state ] [ i ] = min { dp [ state' ] [ j ] + dis [ i ] [ j ] }

其中 state' 是 state 去掉 i 点的集合 , state必然包含 i 和 j

我们尝试证明上述方程的正确性:

每次从子集中转移,那么每次转移时,每个子集都有答案,就是正确的

边界:dp [ { i } ] [ i ] = dis [ 0 ] [ i ]

最后输出最后的状态到0点的最小代价即可

/* A - Hie with the Pie */
/* TSP问题,状压DP,状态表示去过的城市 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
int n;
int dis[15][15];
/* 第一维表示状态,第二维表示要到的城市 */
int dp[1 << 12][15];

int main()
{
    while (~scanf("%d", &n) && n)
    {
        std::memset(dis, 0, sizeof(dis));
        std::memset(dp, -1, sizeof(dp));

        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++) /* Floyd跑最短路,预处理 */
            for (int i = 0; i <= n; i++)
                for (int j = 0; j <= n; j++)
                    dis[i][j] = std::min(dis[i][j], dis[i][k] + dis[k][j]);

        dp[1][0] = 0;                            /* 边界 */
        for (int i = 1; i < (1 << (n + 1)); i++) /* 状态枚举 */
        {
            i |= 1;
            for (int j = 0; j <= n; j++)
                if (dp[i][j] != -1)
                    for (int k = 0; k <= n; k++)
                        if (j != k && (dp[i | (1 << k)][k] == -1 || (dp[i | (1 << k)][k] > dp[i][j] + dis[j][k])))
                            dp[i | (1 << k)][k] = dp[i][j] + dis[j][k];
        }

        std::cout << dp[(1 << (n + 1)) - 1][0] << '\n';
    }
}

转载于:https://www.cnblogs.com/wyctstf/p/11341552.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值