题解: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
posted @ 2026-02-26 11:48  团爸讲算法  阅读(0)  评论(0)    收藏  举报