原題鏈結給定一張 n 個點的帶權無向圖,點從 0~n-1 標號,求起點 0 到終點 n-1 的最短hamilton路徑。 hamilton路徑的定義是從 0 到 n-1 不重不漏地經過每個點恰好一次。
輸入格式
第一行輸入整數n。
接下來n行每行n個整數,其中第i行第j個整數表示點i到j的距離(記為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路徑的長度。
資料範圍
1≤n≤20
0≤a[i,j]≤107
參考思路np hard問題,暴力時間複雜度o(n∗n!)o(n∗n!)
這題正解其實是利用狀壓dp的方法來做,狀態轉移方程為
dp[i][j] = min
其中map陣列為權值,map[k][j]
是點k
到點j
的權值
dp[i][j]
表示當前已經走過點的集合為i
,移動到j
。所以這個狀態轉移方程就是找乙個中間點k
,將已經走過點的集合i中去除掉j
(表示j不在經過的點的集合中),然後再加上從k到j的權值
問題在於如何表達已經走過點的集合i,其實很簡單,假如走過0,1,4這三個點,我們用二進位制10011就可以表示,2,3沒走過所以是0
那麼走過點的集合i中去除掉點j也很容易表示i - (1 << j)
,比方說i
是,
j
是1,那麼i = 10011,(1 << j) = 10,i - (1 << j) = 10001
那麼問題的答案就應該是dp[01....111][n-1]
,表示0~n-1
都走過,且當前移動到n-1
這個點
分析一下時間複雜度,n為20的時候,外層迴圈(1<<20)
,內層迴圈20
,所以整體時間複雜度o(20∗220)
,這比o(n∗n!)
快多了
#include#include#include#include#include#include#include#include#include#include#includetypedef long long ll;
using namespace std;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const double eps=1e-6;
const int maxn=23;
int n;
int mp[maxn][maxn];
int dp[1<<20][maxn];
int main()
AcWing 91 最短Hamilton路徑
91.最短hamilton路徑 給定一張 nn 個點的帶權無向圖,點從 0 n 1 標號,求起點 0 到終點 n 1 的最短hamilton路徑。hamilton路徑的定義是從 0 到 n 1 不重不漏地經過每個點恰好一次。輸入格式 第一行輸入整數nn。接下來nn行每行nn個整數,其中第ii行第jj...
AcWing 91 最短Hamilton路徑
狀壓dp 二進位制 給定一張 n 個點的帶權無向圖,點從 0 n 1 標號,求起點 0 到終點 n 1 的最短 hamilton 路徑。hamilton 路徑的定義是從 0 到 n 1 不重不漏地經過每個點恰好一次。輸入格式 第一行輸入整數 n。接下來 n 行每行 n 個整數,其中第 i 行第 j ...
AcWing 1134 最短路計數
題目描述 給出乙個 n 個頂點 m 條邊的無向無權圖,頂點編號為 1 到 n。問從頂點 1 開始,到其他每個點的最短路有幾條。輸入格式 第一行包含 2 個正整數 n,m,為圖的頂點數與邊數。接下來 m 行,每行兩個正整數 x,y,表示有一條頂點 x 連向頂點 y 的邊,請注意可能有自環與重邊。輸出格...