算法题 | 动态规划-最短hamilton路径

题目: 91. 最短Hamilton路径 - AcWing题库icon-default.png?t=M85Bhttps://www.acwing.com/problem/content/description/93/

思路分析: 

用f[i, j] 表示 我们目前走过的所有点的路径, 以下思路来自acwing y总讲解, 整理成文字: 

状态表示:

  • 集合: 所有从0开始走到j, 走过的所有点存在i当中的所有路径

    • i是一个二进制数 每一位分别表示当前点是不是走过了. i是一个压缩的状态

    • 比如: i=(1110011) 1代表该点走过了 0代表没走过

  • 属性: min

状态计算:

  • 由于最后一个点是确定已知的, 所以以倒数第二个点是哪个点来分类

  • f[i,j]的分类方法: 以倒数第二个点是0/1/2/...n-1 点分类, 倒数第二个点设为k

  • 距离是 f [i 除去j点的状态, k] + a(k,j)

 

 

代码:

代码来自y总和acwing的两个题解, 两位都写的很详细:AcWing 91. 最短Hamilton路径(超详解) - AcWingicon-default.png?t=M85Bhttps://www.acwing.com/solution/content/18533/

AcWing 91. 最短Hamilton路径 - AcWingicon-default.png?t=M85Bhttps://www.acwing.com/solution/content/789/

我通过他们俩的内容进行了一些注释的修改, 方便自己理解, 整理成下面的内容: 

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 20, M = 1 << N;

int n;//点的数量
int w[N][N];//w数组代表两点之间的距离 也就是无向图
int f[M][N];//f数组存的是dp的状态 一维存储的是状态/情况数 二维存储的是距离

int main() {
    cin >> n;//输入点的数量
    //遍历 输入点之间的距离
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> w[i][j];
    //初始化数据
    memset(f, 0x3f, sizeof f);//因为题目需要求最小值 初始化为一个无穷大值0x3f
    f[1][0] = 0;//0点是起点,从0走到0, 状态是1距离是0, 不需要任何做功 就初始化成0
    for (int i = 0; i < 1 << n; i++)//i表示所有的情况/状态的集合, 每一个二进制位是1或0代表这个点是否经过
        for (int j = 0; j < n; j++)//j表示当前枚举哪一个点
            if (i >> j & 1)//如果i状态的第j位为1,也就是到达过j点, 即点j在状态i里经过了
                for (int k = 0; k < n; k++)//枚举j的前一个点k, k表示走到j这个点之前,以k为终点的最短距离
                    if (i >> k & 1)//如果j状态的第k位是1, 也就是j路线到达过k点
                        f[i][j] = min(f[i][j], f[i - (1 << j)][k] + w[k][j]);//状态转移 更新最短距离
                        //f[i][j]是之前的最短距离
                        // f[i - (1 << j)][k]是以倒数第二个点为终点的最短距离, w[k][j]是最后一段的最短距离

    cout << f[(1 << n) - 1][n - 1] << endl;//输出最后的最优值 表示所有点都走过了,且终点是n-1的最短距离
    //位运算的优先级低于'+'-'所以有必要的情况下要打括号
    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值