题解:AcWing 91 最短Hamilton路径
【题目来源】
Acwing:91. 最短Hamilton路径 - AcWing题库
【题目描述】
给定一张 \(n\) 个点的带权无向图,点从 \(0\sim 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]\ge a[x,z]\)。
【输出】
输出一个整数,表示最短 Hamilton 路径的长度。
【输入样例】
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
【算法标签】
《AcWing 91 最短Hamilton路径》 #二进制# #状态压缩DP#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 20, M = 1<<N; // N 表示最大点数,M 表示最大状态数(2^N)
int n; // n 表示点的数量
int w[N][N]; // w[i][j] 表示点 i 到点 j 的权重(距离或代价)
int f[M][N]; // f[i][j] 表示在状态 i 下,到达点 j 的最小代价
int main()
{
cin >> n; // 输入点的数量
// 读取权重矩阵
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
cin >> w[i][j]; // 输入点 i 到点 j 的权重
// 初始化动态规划数组
memset(f, 0x3f, sizeof(f)); // 将 f 数组初始化为一个较大的值(无穷大)
f[1][0] = 0; // 初始状态:从1走到j,走过所有点是 1 的所有路径的代价为 0
// 动态规划求解最小代价
for (int i=0; i<1<<n; i++) // 遍历所有可能的状态
for (int j=0; j<n; j++) // 遍历所有点
if (i>>j & 1) // 检查状态 i 是否包含点 j
for (int k=0; k<n; k++) // 遍历所有可能的上一状态点 k
if ((i-(1<<j)) >> k & 1) // 检查状态 i 去掉点 j 后是否包含点 k
f[i][j] = min(f[i][j], f[i-(1<<j)][k] + w[k][j]); // 更新状态转移方程
// 输出结果
cout << f[(1<<n)-1][n-1] << endl; // 输出最终结果:经过所有点并回到终点的最小代价
return 0;
}
【运行结果】
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
浙公网安备 33010602011771号