最短Hamilton路径
给定一张 nn 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。
输入格式
第一行输入整数n。
接下来n行每行n个整数,其中第ii行第jj个整数表示点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]≤10^7
输入样例:
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
最朴素的做法就是枚举 n 个点的全排列, 计算路径的长度取最小值, 时间复杂度为O(n*n!).但使用状态压缩可以优化到 O(n^2 *2^n)
在任意时刻如何表示那些点已经经过?哪些点没有被经过? 可以用一个n位的二进制数来表示, 如果第 i 位 是 1 ,则表示第i 个点已经经过,f[i][j] 表示"点被经过的状态"对应的二进制表示为 i , 且目前处于点 j 时 的最短路径 .
在起点的时候 , 有 F[1,0 ] = 0 ,表示 只经过了点0 (i 只有第0 位为1 , F[ 1,0] 中的 1 其实就是 00001 ,有几位二进制看你顶点的个数 ) , 目前处于起点 0 , 最短路为0 . 方便起见 , 我们将 F 数组 其他的值设为 无穷大 . 最终我们要求的是到终点 顶点 n-1 的最短路, 也就是 F [ (1< 状态方程 : ,其中 (0<= k <=n 并且 ((i>>j )&1 ) = 1 ) ,即当前时刻"被经过的点的状态" 对应二进制数位 i ,处于点 j . 这里 (n >>k ) & 1 表示 取出整数 n 在二进制下的第 k 位 ; (n xor 1 < 因为 j 只能被恰好经过一次(题目中要求的,每个顶点只经过一次 ) ,所以一定是刚刚经过的,故在上一时刻" 被经过的点的状态"对应的二进制的第 j 为 应该赋值为0 就是 (i xor (1< 所以代码中第一重循环枚举的是点被经过的状态, 第二重循环时枚举当前处于哪个顶点 , 第三重 枚举的是上一状态中任意已经 经过的点 ;
#include