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
题解
本题如果用朴素算法枚举每一种路径,找最小值时间复杂度为
用状态压缩DP复杂度为
状态转移方程
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]); }