AcWing 91. 最短Hamilton路径
以下皆参考自y总的视频讲解
1. 问题定义
最短Hamilton路径:
在 n 个点的带权无向图中,起点为0,走完所有点的最小边权和。
这是一个NP问题,即时间复杂度为多项式时间的非确定问题。
简单来说就是没有一个满足多项式时间的解法。
什么是多项式时间:机器上最小的时间复杂度级别,与之对应的是超多项式时间。
什么是超多项式时间:解题时间会大大超过任何多项式时间的问题,比如指数级别的时间复杂度问题。
2. 问题分析
由于没有满足多项式时间解法,这个问题只能采用暴力解法
暴力枚举的时间复杂度是 n!
本题数据 n <= 20 也就是最高 20! 大概是2 * 10^18
本题时间限制为5s 1秒按照常规计算速度 10^8 来算 最高是5 * 10^8
明显暴力解法不可取
对问题进行梳理
假设有4个点 0 1 2 3
0这个点是固定的
所以有 3! = 6 种路径
0->1->2->3 0->1->3->2
0->2->1->3 0->2->3->1
0->3->1->2 0->3->2->1
因为在暴力dfs过程中,我们只关心两个状态
- 已经访问过哪些点
- 目前停留在哪个点上
考虑设置一个二维状态数组 分别表示两个状态
定义dp[state_i][i]
表示当遍历到i
这个点时的最小边权和
其中state_i
中表示访问过的点(包括 i 本身这个点)
那要如何得到当前的最小边权和?
肯定是除了目前这个点 所有已经访问过的点的最小边权值 加上当前边权
就是我们要的当前最小边权值 也就是用已有值(旧状态)来更新当前值(新状态)
可以得到状态转移方程为
dp[state_i][i] = dp[state_k][k] + weight[k][i]
其中dp[state_k][k]
表示除了i
这个点
所有访问过的点的最小边权值weight[k][i]
为k
到i
的边权值
3. 状态表示与压缩
到这里还剩下一个问题没有解决:
如何用一个数表示访问过的点state_i
?
既然一个点只有两种状态,访问或者未访问
可以借助只有两种状态的二进制 (0,1)
计算机一个整型数有4个字节32位 题目最大20个点
也就是可以用一个整型数里面的20位来表示20个点的状态
来达到压缩状态总大小的目的
其中0表示未访问 1表示已访问
要查看 x 这个点的状态 也就是取二进制中第 x 位的值
可以这样做
state_i >> x & 1
表示一个数向左位移x
位之后,此时第x
位在最低位,然后&1
取最低位
比如当前state_i
= 6(十进制) = 0110(二进制)
要查看第 2 这个点 也就是
6 >> 2 = 0110 >> 2 = 01
取最低位
01 & 1 = 1
表示 2 这个点已经被访问过了
4. 初始情况
开始的时候 只有0这个点被访问 且边权为0
二进制第0位设置为1 也就是十进制的1
不要忘记先给状态数组赋初值~
题目求最小值 所以初值设置为较大数
5. 时间复杂度
最后分析一下该方法的时间复杂度
<