【AcWing 91】 最短Hamilton路径 状压DP + 位运算 详解

给定一张 n 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。

输入格式
第一行输入整数n。

接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(记为a[i,j])。

对于任意的x,y,z,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]>=a[x,z]。

输出格式
输出一个整数,表示最短Hamilton路径的长度。

数据范围
1≤n≤20
0≤a[i,j]≤107
输入样例:
5
0 2 4 5 1
2 0 6 5 3
4 6 0 8 3
5 5 8 0 5
1 3 3 5 0
输出样例:
18

题意:如题

思路:

一道NP完全问题。别看数据量小,暴力的话,时间复杂度是O(n * n!),光是一个20的阶乘就已经到1018了!!!
毫无疑问,这道题要借助算法的思想尽量地优化。首先我们发现,我们并不需要知道这个方案是如何选择的(顺序),而是只需要解得最优解即可。所以,我们无非要解决两个问题
1.当前选了哪些点?
2.对这些选的点进行路径优选
第一个,我们有20个点,如果用数组下标表示每个点的选择情况的话,那得开220维度的数组(a[1][0][0][1]…[1],20维,每维两层),1表示选,0表示不选。220的大小,虽说开得到这么大的数组,但是未免过于麻烦(不会有人能开着20维数组写代码吧?不会吧?)。但是注意到,我们的情况就是一个01问题——选与不选。这就对应到了二进制。比如前面说的这个做例子a[1][1][0][1],我们开了前四维,表示的是1101,就是选了3 2 0位置的意思(这三个位置上为1),但是,我们似乎不用这么麻烦。直接a[1101]不就行了吗?数据量上限仍然是220,那我们就开一个这么大的一维数组,下标用来存对应的二进制数,然后要第j个点选择,就直接将下标右移j位,这时候最右边的就是你要的第j个(通过&1判断是否为1)。
解决了第一个问题,也就是存储的问题。也就是用a[i]表示i集合,这个i集合存储的是一个二进制信息,代表我选了哪几个点。然后我们现在要对每个选了的点进行状态转移。那就需要多开一维。a[i][j],来表示我i集合中对第j位进行优选。
那么怎么对a[i][j]进行状态转移呢?我们无非就是要找一个中间状态k,看看k->j的花费加上原来选到k而没有j的花费会不会比我当前的选择少。也就是,如果我k这个位置的点已经在集合里面的话,就看看k-<j这条路径能否转移到我当前的最优解中。
这部分转化成代码就是

if (i >> k & 1)       //你要从k状态转移的前提是k这个位置的点有选择
        f[i][j
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值