AcWing 91. 最短Hamilton路径
作者:互联网
今天第一次在\(AcWing\)这个网站上做题,来发一下此网站的第一篇题解
传送门
思路
直接枚举的话时间复杂度为\(O(n*n!)\)
复杂度显然爆炸,所以我们用二进制枚举,这样就可以把复杂度降到\(O(n * 2^{n})\)
我们用\(f[i][j]\)表示走到j这个点,经过点的状态为\(i\)(\(i\)是二进制数,若\(i\)的二进制数下某一位为\(1\)则表示这个点已经走过了)
显然,转移方程为:\(f[i][j] = min(f[i][j], f[i ^ 1 << j][k] + a[k][j])\)(\(k\)为上一步走的点,\(i\)中必须包含\(k\)的时候才可以转移,这里加一个判断就好了)
最后的答案就存在\(f[(1<<n)-1][n-1]\)中(因为我这里是从\(0\)开始编号的)
代码
//知识点:二进制状态压缩
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 20;
int n, a[N][N], f[1 << N][N];
int main() {
n = read();
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
a[i][j] = read();
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] + a[k][j]);
cout << f[(1 << n) - 1][n - 1] << '\n';
return 0;
}
标签:include,二进制,复杂度,int,isdigit,Hamilton,91,getchar,AcWing 来源: https://www.cnblogs.com/loceaner/p/11656478.html