状态压缩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

思路:将每种走法压缩成为二进制表示,其中共有2n-1中表示方法。
状态表示:f[i][j]表示从第0个点到第j个状态为i的最短距离
状态转移: 求所有从第0个点到第j个点,且倒数第二个点是k的距离的最小值(状态中包括第k个点)
代码实现:

#include
#include
#include
#include
#include
using namespace std;

const int N = 20;
const int M = 1<<N;
int f[M][N];//f[i][j]表示从第0个点到第j个状态为i的最短距离 
int a[N][N];
int n,m;
int main(){
	int i,j,k;
	
	cin>>n;
	for(i = 0;i<n;i++){
		for(j = 0;j<n;j++){
			scanf("%d",&a[i][j]);
		}
	}
	memset(f,0x3f,sizeof(f)) ;
	for(i = 1;i<n;i++){
		f[(1<<i)+1][i] = a[0][i];
		int c = (1<<i)+1;
	//	cout<
	}
	for(i = 0;i<1<<n;i++){
		//如果第0位不是1则continue; 
	//	if((i&1)==0)continue;
		for(j = 1;j<n;j++){//j从1开始,因为第0个点是起点 
			//如果状态内不包括第j个点就continue 
			if((i>>j & 1)==0)continue;
			for(k = 1;k<n-1;k++){
				//如果状态内不包括第k个,continue
				if((i>>k & 1) == 0)continue; 
				//求所有从第0个点到第j个点,且倒数第二个点是k的距离的最小值 
				int t = i^(1<<j);//将i的第j为翻转为0 
				//也可以写成t = i-(1<
				f[i][j] = min(f[i][j] , f[t][k]+a[k][j]);
			}
		}
	}
	cout<<f[(1<<n)-1][n-1];
	return 0;
}



你可能感兴趣的:(ACM,算法,c++,动态规划)