91. 最短Hamilton路径【状压DP】

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

输入格式

第一行输入整数nn。

接下来nn行每行nn个整数,其中第ii行第jj个整数表示点ii到jj的距离(记为a[i,j])。

对于任意的x,y,zx,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

本题如果用朴素算法枚举每一种路径,找最小值时间复杂度为O\left ( n * n! \right ) 

用状态压缩DP复杂度为O\left ( 20*2^{20} \right )

状态转移方程 dp[i][j] = min(dp[i][j], dp[i\oplus (1 << j)][k] + a[k][j]);

i 表示 方案集合  j表示枚举的点   k 表示j的上一个点 

关于位运算  

( n >> k ) & 1  表示n在二进制表示下的第k位

n ^ ( 1 << k ) 表示n 在二进制表示下的第k位取反

#include <iostream>
#include <cstdio>       //EOF,NULL
#include <cstring>      //memset
#include <cmath>        //ceil,floor,exp,log(e),log10(10),hypot(sqrt(x^2+y^2)),cbrt(sqrt(x^2+y^2+z^2))
#include <algorithm>    //fill,reverse,next_permutation,__gcd,
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define rep(i, a, n)		for (int i = a; i < n; ++i)
#define sca(x)			scanf("%d", &x)
#define sca2(x, y)		scanf("%d%d", &x, &y)
#define sca3(x, y, z)		scanf("%d%d%d", &x, &y, &z)
#define pri(x)			printf("%d\n", x)
#define pb	push_back
#define mp	make_pair
typedef pair<int, int>		P;
typedef long long		ll;
int dp[1 << 20][20];
int n;
int a[20][20];
int main()
{
	sca(n);
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			sca(a[i][j]);
		}
	}
	memset(dp, 0x3f, sizeof dp);
	dp[1][0] = 0;
	for (int i = 0; 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) {
						dp[i][j] = min(dp[i][j], dp[i ^ 1 << j][k] + a[k][j]);
					}
				}
			}
		}
	}
	pri(dp[(1<<n)-1][n-1]);
}
发布了89 篇原创文章 · 获赞 6 · 访问量 7920

猜你喜欢

转载自blog.csdn.net/kl782636177/article/details/89399449