位運算_CH0103_最短Hamilton路徑
阿新 • • 發佈:2018-12-16
思路分析:
本題是典型的二進位制狀態壓縮DP問題(為方便敘述, 約定點i表示編號為i的點, 整數的最低位為第0位), 設F[i][j]表示從點0的點出發到點j, 且經過點的狀態為i的最短路徑長(路徑上所有邊的權值之和), 是如何表示經過點的狀態的? 如果i的第k(k >= 0)位為1那麼該路徑經過點k, 為0則不經過點k, 最終需求得F[(1 << n) - 1][n - 1] 欲求F[i][j], 可考察其對應路徑的倒數第2個頂點(如果存在)t, 初始化F[1][0]為0, 下面給出狀態轉移方程:
注意: i & ~(1 << j)表示將i的第j位賦0得到的值, weight[t][j]表示邊<t, j>(如果存在)的權值
F[]i][j] = min{ F[i & ~(1 << j)][t] + weight[t][j] | t j, i 的第j位為1, i的第t位為1, 存在邊<i, j>}
下面給出AC程式碼:
//CH0103_最短Hamilton路徑 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX = 20; int F[1 << MAX][MAX], weight[MAX][MAX]; int main(){ int n; scanf("%d", &n); for(int i = 0; i < n; ++i) for(int j = 0; j < n; ++j) scanf("%d", &weight[i][j]); memset(F, 0x3f, sizeof(F)), F[1][0] = 0;//前者將F中所有元素初始化為正無窮大, 是必要的 for(int i = 2; i < (1 << n); ++i) for(int j = 0; j < n; ++j) if((i >> j) & 1) for(int t = 0; t < n; ++t) if(j != t && (i >> t) & 1) F[i][j] = min(F[i][j], F[i & ~(1 << j)][t] + weight[t][j]); cout << F[(1 << n) - 1][n - 1] << endl; return 0; }
對於上述演算法的時間複雜度, 顯然為O()