最短Hamilton路径

Posted KylinLzw (●—●)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短Hamilton路径相关的知识,希望对你有一定的参考价值。

最短Hamilton路径

二进制状态压缩的应用
Hamilton路径的定义是从0到n-1不重不漏地经过每个点一次。

思路
我们可以采用一个n位的二进制数,用其第i(0<=i< n)为1表示第i个点已经被经过,0表示还没被经过,这样我们可以使用f[i,j] (0<=i<2^n,0<=j< n)表示二进制i时,且目前处于j点的最短路径,这样n位全是1的状态代表的是经过所有点的最短路状态。

1.初始化:先把f数组初始化成正无穷,f[1,0]=0表示在起点0,最短路径也是0。
2.转移方程:f[i,j]=min(f[i xor (1<< j),k]+weight(k,j)),其中0<=k< n并且(i>>j)&1=1。(解释:当前的j点必须是第一次经过并且只能是经过一次,所以转移而来的状态必须是j点还没经过,但是目前的i位置则是j已经经过的状态,也就是i xor (1<< j)。另外,上一时刻的位置是任意一个是1的数位k,从k走到j需要经过的路程为weight(k,j)取最小值。
3.最终状态:f[(1<<n)-1,n-1]表示经过所有的点并且位于n-1的位置。

int Hamilton()
//初始化
    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-(1<<j)][k]+weight[k][j],f[i][j]);
//返回答案
    return f[(1<<n)-1][n-1];

模板题:

ACWing 91. 最短Hamilton路径
传送门

#include<iostream>
#include<cstring>
using namespace std;
const int N=1<<21,M=21;
int weight[22][22],f[N][M];
int n;
void Hamilton()
    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-(1<<j)][k]+weight[k][j],f[i][j]);

int main()
    cin>>n;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)cin>>weight[i][j];
    
    Hamilton();
    cout<<f[(1<<n)-1][n-1]<<endl;
    

以上是关于最短Hamilton路径的主要内容,如果未能解决你的问题,请参考以下文章

《算法竞赛进阶指南》-AcWing-91. 最短Hamilton路径-题解

『最短Hamilton路径 状态压缩DP』

最短Hamilton路径-状压dp解法

# 最短Hamilton路径(二进制状态压缩)

最短Hamilton路径

最短Hamilton路径