Hie with the Pie(Floyd 状压DP)
POJ 3311 Hie with the Pie
題目大意
一個披薩店要請司機來送披薩,這家店最多接受10個訂單,由于預算的問題,只能雇傭一名司機,要求用最短的時間,從披薩店出發送完最后再回到披薩店(途中可能不止一次經過一個地方)。
輸入
測試數據可能有多個,第一行包含一個整數 n n n ( 1 ≤ n ≤ 10 1 \leq n \leq 10 1≤n≤10),接下來的 n + 1 n+1 n+1行,每行包含 n + 1 n+1 n+1個整數,披薩點的位置 0 0 0以及后面 n n n個位置,其中第 i i i行第 j j j個值表示從位置 i i i到達位置 j j j所用的時間(其中對于從 i i i到 j j j可能有更快捷的方式,數據不是對稱的),當 n = 0 n=0 n=0時,表示輸入結束
輸出
對于每一個測試用例輸出一個整數,表示所花費的最短的時間
樣例輸入
3 0 1 10 10 1 0 1 2 10 1 0 10 10 2 10 0 0樣例輸出
8分析
由于每兩個地點的直接距離不一定是最短的,因此首先要用 f l o y d floyd floyd算法來更新所有點之間的最短距離
然后這個問題就變成了典型的 T S P TSP TSP問題,為了便捷的表示已經被訪問過的位置,可以使用二進制來進行壓縮,例如有 4 4 4個位置,分別是 0 , 1 , 2 , 3 0,1,2,3 0,1,2,3,其中 1 1 1和 2 2 2已經被訪問過,那么二進制表示為 ( 0110 ) 2 (0110)_2 (0110)2?,被訪問過的頂點就用 1 1 1表示,沒訪問過的用 0 0 0表示。這樣就可以將狀態壓縮到一個數組中去。就可以清楚的表示哪些頂點被訪問過,哪些沒有被訪問。
其中 d [ s ] [ j ] d[s][j] d[s][j]表示,在當前的 s s s的狀態下(已經訪問過的點),正處在 j j j的位置上回到頂點所花費的最小時間。狀態轉移方程如下
d [ s ∣ 1 < < k ] [ k ] = m i n ( d [ s ∣ 1 < < k ] [ k ] ,    d [ s ] [ j ] + a [ j ] [ k ] ) d[s|1<<k][k] = min(d[s|1<<k][k],\,\,d[s][j]+a[j][k]) d[s∣1<<k][k]=min(d[s∣1<<k][k],d[s][j]+a[j][k])
其中點 k k k表示下次要訪問的點,是從已經訪問過的點 j j j轉移到下一個點 k k k。更新完數組后
最終答案就是,枚舉所有的 d [ ( 1 < < n ) ? 1 ] [ i ] + a [ i ] [ 0 ]        ( 0 < i < n ) d[(1 << n) - 1][i] + a[i][0]\,\,\,\,\,\,(0<i<n) d[(1<<n)?1][i]+a[i][0](0<i<n),其中最小值就是答案。這句話的意思就是,訪問所有頂點后,可能停留再任意一個地方 i i i,因此要枚舉每一個地方回到 0 0 0的時間。
代碼
#include <cstdio> #include <cstring> #define N 11 #define INF 0x3f3f3f3f #define min(a,b) a>b?b:aint a[N][N]; int d[1 << N][N]; int n;inline void floyd() {for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)for(int k = 0; k < n; k++)a[i][j] = min(a[i][j], a[i][k] + a[k][j]); }int main () {while(1) {scanf("%d", &n);if(!n) break;n++;memset(d, INF, sizeof(d)); //初始化d[1][0] = 0; //從0出發,二進制中1表示第一個位置訪問過,所以置為0for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)scanf("%d", &a[i][j]);floyd();for(int s = 0; s < 1 << n; s++)for(int j = 0; j < n; j++)if(s >> j & 1) //找到已經訪問過的點jfor(int k = 0; k < n; k++)if(!(s >> k & 1)) //找到沒有被訪問過的點kd[s|1 << k][k] = min(d[s|1 << k][k], d[s][j] + a[j][k]); //從j點更新到k點int ans = INF;for(int i = 1; i < n; i++)ans = min(ans, d[(1 << n)-1][i] + a[i][0]);printf("%d\n", ans);}return 0; }總結
以上是生活随笔為你收集整理的Hie with the Pie(Floyd 状压DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: syzkaller--->syscall
- 下一篇: Linux设备类型有哪些?