哈密頓回路


旅行商問題

求解從一點出發經過其它各點僅一次並回到出發點的最短路徑
當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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM