问题描述
给定一张 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≤201≤n≤20
0≤a[i,j]≤1070≤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
思路:
首先如果是暴力解的话复杂度大约是20! (2.4*10^18)根本不可能实现
然后我们降低复杂度,这个题我用的算法是状态压缩dp,
用f[i][j]表示当前已经走过点的集合为i,移动到j。所以这个状态转移方程就是找一个
中间点k,将已经走过点的集合i中去除掉j(表示j不在经过的点的集合中),然后再加上
从k到j的权值
状态转移方程:f[i][j] = min( f[i][k] + 从k到j的距离 , f[i][j] ) K是 i去掉j之后 的子集
怎么表示集合? 用位运算表示
假设给定20个元素,我们用二进制中0来表示元素未被选定,用1表示选定
例如:20个元素的子集有2^20个左右,我们用一个20位的二进制数来表示该集合
第i位的 0 与 1 表示第 i 个元素是否被选定,
假设已经走过1,,3,4这几个点,那么i就是 11010
那么怎么枚举所有走过的点的集合
对于任意i,判断( i >> x & 1 )的值是否为1 来确定第x位是1还是0 进而确地第x的点是否被走过
代码如下,还是看代码吧
#include<iostream>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<string>
#include<cstdio>