1. 程式人生 > 其它 >最短Hamilton路徑(c++)——(動態規劃加位運算)

最短Hamilton路徑(c++)——(動態規劃加位運算)

技術標籤:演算法競賽進階指南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及之前所有的點的最小路徑值