#include<iostream>
#include<algorithm>
using namespace std;
const int N = 20, M = 1 << 20;
//20位從右到左表示從低到高的20個點的id
int n;
int f[M][N], weight[N][N];
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> weight[i][j];
}
}
memset(f, 0x3f, sizeof f);
f[1][0] = 0;
for (int i = 0; i < 1 << n; i++) {
for (int j = 0; j < n; j++) {//用j枚舉
if (i >> j & 1) {//檢查第j位
for (int k = 0; k < n; k++) {
if ((i - 1 << j) >> k & 1) {//j的前驅k 因爲已經枚舉到j這個點了,所以要將它刪掉後,再檢查第k位
f[i][j] = min(f[i][j], f[i - 1 << j][k] + weight[k][j]);//移位運算符優先級高於加減
}
}
}
}
}
cout << f[(1 << n) - 1][n - 1];
return 0;
}
最短Hamilton路徑
本題如果使用暴搜的話會超時。因爲是無向圖,所以最終我們只關心不重不漏的一條路徑的長度,而不關心內部先走哪個點後走哪個點。所以,我們需要對每個點進行位置標記,當然可以開一個visited數組記錄,但爲了操作簡便以及空間複雜度,使用二進制位表示更爲簡便。某一位爲1表示對應的該點被訪問過。因此一個二進制數就代表了一種路徑狀態。這就是狀態壓縮。狀態轉移方程爲f[i][j] = min(f[i][j], f[i-1 << j][k] + weight[k][j])。另外值得注意的是,移位運算符的優先級高於加減運算符。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.