1. 程式人生 > WINDOWS開發 >AcWing 91 最短Hamilton路徑(狀壓dp)

AcWing 91 最短Hamilton路徑(狀壓dp)

題目連結

解題思路

??狀壓dp入門題,也是經典的tsp問題。因為tsp問題是np完全問題,所以我們只能考慮通過大量列舉來做。需要注意的一點是,如果走過了1->2->3這樣一條路徑,要到達第4個點的話,並不一定需要從3出發,只要從前面走過的點出發即可,所以我們並不需要把所以的點按前後順序走出來的情況全部枚舉出來。
??考慮最後一步的情況,我們已經走過了N-1個點,要訪問最後一個點,那麼結果就是從之前N-1個點之中的一個走過來的最小值。所以問題就是如何表示前面已經走過了哪些點。這裡用狀壓dp的方法,把二進位制數的1表示訪問過,0表示位訪問過,以dp[state][k]表示當前狀態最後到達k點的總花費,那麼狀態轉移方程就是dp[i][j] = min(dp[i][j],dp[i-(1<<j)][k]+w[k][j])

int dp[1<<20][20],w[20][20];
int main(void) {
    int n; scanf("%d",&n);
    for (int i = 0; i<n; ++i)
        for (int j = 0; j<n; ++j) scanf("%d",&w[i][j]);
    INF(dp); dp[1][0] = 0; 
    for (int i = 3; 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) dp[i][j] = min(dp[i][j],dp[i-(1<<j)][k]+w[k][j]);
                    //j是列舉結尾的點,而k是列舉上一個狀態的點
            }
    printf("%d\n",dp[(1<<n)-1][n-1]);
    return 0;
}