最短Hamilton路徑(c++)——(動態規劃加位運算)
最短Hamilton路徑
時間限制:4Sec記憶體限制:128 MB
題目描述
給定一張 n(n≤20) 個點的帶權無向圖,點從 0~n-1 標號,求起點 0 到終點 n-1 的最短Hamilton路徑。 Hamilton路徑的定義是從 0 到 n-1 不重不漏地經過每個點恰好一次。
輸入
第一行一個整數n。
接下來n行每行n個整數,其中第i行第j個整數表示點i到j的距離(一個不超過10^7的正整數,記為a[i,j])。
對於任意的x,y,z,資料保證 a[x,x]=0,a[x,y]=a[y,x] 並且 a[x,y]+a[y,z]>=a[x,z]。
輸出
一個整數,表示最短Hamilton路徑的長度。
樣例輸入
4 0 2 1 3 2 0 2 1 1 2 0 1 3 1 1 0
樣例輸出
4
已AC程式碼
#define LL long long #include <bits/stdc++.h> using namespace std; int w[21][21]; int dp[21][(1 << 20)+5]; int main(){ int n; cin >> n; for(int i=0;i<n;++i) for(int j=0;j<n;++j) cin >> w[i][j]; memset(dp,0x3f,sizeof(dp)); dp[0][1] = 0; for(int i=1;i<(1 << n);++i){ for(int j=0;j<n;++j){ if((1 << j) & i){ for(int k=0;k<n;k++){ if(j == k) continue; if((1 << k) & i){ dp[j][i] = min(dp[j][i],dp[k][(1 << j) ^ i] + w[k][j]); } } } } } cout << dp[n-1][(1 << n) - 1]; return 0; }
思想
1、記錄兩個狀態:經過了哪些點,現在在那個點上。
2、用動態規劃——狀態壓縮,用二進位制數記錄狀態。
例如:有四個點A,B,C,D,0101是數5,代表著經歷了A點和C點。
3、用位運算:判斷和篩選正確的經歷狀態。
4、進行最小值重新整理。
注意點
1、#include<bits/stdc++.h>
儘量少用,因為引入的標頭檔案太多,影響編譯速度,在打比賽時,會拖節奏
2、intdp[21][(1<<20)+5];
1<<21太大,會超限
3、memset(dp,0x3f,sizeof(dp));
0x代表該數是16進位制,0x3f預設補成0x3f3f3f3f,接近int型最大值的一半
4、if((1<<j)&i)
此語句用來判斷是否到過j點,如果沒到過,則不是合法的資料,不用賦值
5、if((1<<k)&i)
此語句用來判斷是否到過k點,如果到過,則重新整理最小路徑值
6、dp[j][i]=min(dp[j][i],dp[k][i-(1<<j)]+w[k][j]);
dp[k][(1<<j)^i] = dp[k][i-(1<<j)]表示此時在k點,經歷了j點之前的所有點的最小路徑值
7、cout<<dp[n-1][(1<<n)-1];
dp[n-1][(1<<n)-1] 表示此時在n-1點上,經歷了n-1及之前所有的點的最小路徑值