哈密顿回路

旅行商问题

求解从一点出发经过其它各点仅一次并回到出发点的最短路径
当n的个数不到时,可通过状压dp求解

状态压缩

将每个点是否访问过编码为0或1,那么当n=4时,访问所有点后的状态为1111,初始时状态为0001。
达到每个状态的最后一步可能是从第1,2,3,4个位置转移过来的,因此我们需要记录达到当前状态时,上次访问的点
由此我们可以写出状态转移方程
dp[t][j]=min(dp[t][j],dp[s][i]+dis[i][j])
由状态转移方程可知我们需要枚举状态s,转移到状态t的上一步j,以及状态s的上一步i

#include<iostream>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int dis[22][22];
//dp[i][j]表示已访问状态为i,上次访问点为j的最小距离
int main()
{
    int n;
    scanf("%d",&n);
    vector<vector<int>> dp(1<<(n),vector<int>(n+1,INF));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&dis[i][j]);
        }
    }
    dp[1][1]=0;
    //枚举状态s,更新从s经过i到下一状态t的最短路径
    for(int s=1;s<(1<<n);s++){
        for(int i=1;i<=n;i++){
            if(s&(1<<(i-1))){
                for(int j=1;j<=n;j++){
                    if(!(s&(1<<(j-1)))){
                        int t=(s|(1<<(j-1))); //新状态
                        //cout<<i<<" "<<j<<" "<<s<<" "<<t<<endl;
                        dp[t][j]=min(dp[t][j],dp[s][i]+dis[i][j]);
                    }
                }
            }
        }
    }
    int ans=INF;
    for(int i=2;i<=n;i++){
        ans=min(ans,dp[(1<<n)-1][i]+dis[i][1]);
    }
    printf("%d\n",ans);
    return 0;
}

posted @ 2020-07-29 15:46  blueattack  阅读(699)  评论(0编辑  收藏  举报