最短Hamilton路径

                                                                                最短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<

状态方程 :

                         F [i,j] = min (F[ i (xor) (1<<j) , k] ,f[i,j] ] )+weight(k,j)  ,其中 (0<= k <=n  并且  ((i>>j )&1 ) =  1 ) ,即当前时刻"被经过的点的状态" 对应二进制数位 i ,处于点 j .

              这里    (n  >>k ) & 1 表示 取出整数  n 在二进制下的第 k 位 ;

               (n xor 1 <

  因为 j  只能被恰好经过一次(题目中要求的,每个顶点只经过一次 ) ,所以一定是刚刚经过的,故在上一时刻" 被经过的点的状态"对应的二进制的第 j 为 应该赋值为0 

  就是 (i xor (1<

所以代码中第一重循环枚举的是点被经过的状态, 第二重循环时枚举当前处于哪个顶点 , 第三重 枚举的是上一状态中任意已经

经过的点 ; 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define Swap(a,b)  a ^= b ^= a ^= b
#define cl(a,b) memset(a,b,sizeof(a))
using namespace std ;
typedef long long LL;
const int N = 1e7+10 ;
const int MAX = 105;
const int inf = 0xffffff;
const LL mod = 1e9+7 ;
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
priority_queue,greater > q ;// 小跟堆
priority_queue Q ; // 大堆
int f[1<<20][20];
int weight[25][25];
int hamilton(int n ){
	memset(f,0x3f,sizeof(f));// 首先把所有的设为无穷大
	f[1][0] = 0 ; // 表示只经过第0个点(i只有第0位为 1 )目前处于起点0 ,最短路径0
	for(int i = 1 ;i< 1<>j &1){ // 被经过的点的状态如果i集合中第j位是1,也就是到达过这个点
			    for(int k = 0 ; k>k &1){
			    		f[i][j] = min(f[i][j],f[i^1<> n ;
    for(int i = 0 ;i>weight[i][j] ;
		}
	}
    cout<

 

 

 

你可能感兴趣的:(Acwing,#,状压dp)