給定一張 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
輸入樣例:
50 2 4 5 1
2 0 6 5 3
4 6 0 8 3
5 5 8 0 5
1 3 3 5 0
輸出樣例:
18問題分析:
對於乙個4個點的帶權無向圖,從點1到點4有兩條路徑,1->2->3->4 和 1->3->2->4 兩條路徑,
這兩條路徑有共同的狀態:
1. 所有點都經歷過一遍
2. 終點相同
所以我們只要記錄經歷過哪些點和終點是誰就可以描述出乙個哈密頓路,至於中間點的遍歷順序就是需要我們遍歷求解最優值的動態規劃的過程。
設我們用乙個32位數status的每一位表示該點是否經過(事實上**就是這麼寫的),
用 f[status][k] 表示 經過status這些點,終點是k的最短長度
狀態轉移方程:f[status][j] = min(f[status - j][k] + weight[k][j]), 遍歷j, j是當前已經過的點的集合
(status - j) 表示 從經過的所有點中去除點j, weight[k][j] 表示從點k到點j的權重
遍歷一遍能到達點 j 的所有狀態,取最小長度就是 status狀態下到達 j 的最小長度。
考點總結:
1. 狀態的抽象,用 f[status][j] 表示(個人感覺是最難的,思路就是平時點滴的積累,不斷地刷題,才知道遇見什麼樣的題目,該往什麼方向去思考)
2. 狀態的表示,採用二進位制表示方式,乙個迴圈便可以遍歷出所有的狀態。
3. 哈密頓圖的相關知識。
詳細**:
/*
f[status][k] status的二進位制每一位 1 表示該點已經過 0表示該點未經過
狀態轉移方程:f[status][j] = min(f[status - j][k] + weight[k][j]), 遍歷j, j是當前已經過的點的集合
*/#include
#include
#include
using namespace std;
const
int m =
1<<20;
const
int n =21;
int f[m]
[n], weight[n]
[n];
intmain()
}}}}
cout << f[(1
<< n)-1
][n -1]
<< endl;
}
最短Hamilton路徑
題目描述 給定一張 n n 20 個點的帶權無向圖,點從 0 n 1 標號,求起點 0 到終點 n 1 的最短hamilton路徑。hamilton路徑的定義是從 0 到 n 1 不重不漏地經過每個點恰好一次。輸入第一行乙個整數n。接下來n行每行n個整數,其中第i行第j個整數表示點i到j的距離 乙個...
最短Hamilton路徑
本題如果使用暴搜的話會超時。因為是無向圖,所以最終我們只關心不重不漏的一條路徑的長度,而不關心內部先走哪個點後走哪個點。所以,我們需要對每個點進行位置標記,當然可以開乙個visited陣列記錄,但為了操作簡便以及空間複雜度,使用二進位制位表示更為簡便。某一位為1表示對應的該點被訪問過。因此乙個二進位...
最短Hamilton路徑
給定一張 n 個點的帶權無向圖,點從 0 n 1 標號,求起點 0 到終點 n 1 的最短hamilton路徑。hamilton路徑的定義是從 0 到 n 1 不重不漏地經過每個點恰好一次。輸入格式 第一行輸入整數n。接下來n行每行n個整數,其中第i行第j個整數表示點i到j的距離 記為a i,j 對...