NCSTOJ 1379 Hamilton路径

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaohaibo_/article/details/82811935
题目描述

给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。

输入

第一行一个整数n。
接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(一个不超过10^7的正整数,记为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路径的长度

样例输入

4
0 2 1 3
2 0 2 1
1 2 0 1
3 1 1 0

样例输出

4


路径压缩DP,f[i][j]:点被经过的状态对应的二进制数为i,目前处于点j时的最短路径。

开始时为f[1][0]=0,即指经过了点0(起点)(i只有第0位为1)。此时的最短路径
为0;

要输出的是f[(1 << n) - 1][n-1]。
例如,n等于5时,1<<5 : 100000 ,表示当前只经过了点5(以5为起点)时的最短路径(f[5][0]=0)。
我们需要输出f[011111][4],即经过了点12345时,且当前在最后一个点时的最短路径。

状态转移方程:f[i][j] = min(f[i][j], f[i ^ 1 << j] [k]+weight[k][j])

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[1 << 20][20], weight[20][20], n;

int hamilton(int n, int weight[20][20]) {
	memset(f, 0x3f, sizeof(f));
	f[1][0] = 0;
	for (int i = 1; i < 1 << n; i++)
		for (int j = 0; j < n; j++) if (i >> j & 1)
			for (int k = 0; k < n; k++) if ((i^1<<j) >> k & 1)
				f[i][j] = min(f[i][j], f[i^1<<j][k]+weight[k][j]);
	return f[(1 << n) - 1][n - 1];
}

int main() {
	cin >> n;
	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
			scanf("%d", &weight[i][j]);
	cout << hamilton(n, weight) << endl;
}

猜你喜欢

转载自blog.csdn.net/zhaohaibo_/article/details/82811935