uva 116 Unidirectional TSP(動態規劃,多段圖上的最短路)

deepwzh發表於2017-02-10

這道題目並不是很難理解,題目大意就是求從第一列到最後一列的一個字典序最小的最短路,要求不僅輸出最短路長度,還要輸出字典序最小的路徑。

這道題可以利用動態規劃求解。狀態定義為:

cost[i][j] = max{cost[i+1][j+k]+c[i][j]}(k=-1,0,1)

關於最短路長度的求法,我們可以通過上邊的狀態轉移方程遞推求解。cost代表從第i列到第c-1列的最短路,只要找出cost[0][j](j代表行號)中的最大值,我們得到的結果就是最短路。

我們已經得到了最短路的長度。下一步,我們應該如何輸出完整的最短路路徑。題目說了最短路可能有多個,並且要求輸出字典序最小的最短路。

如何得到字典序最小的最短路?

要讓字典序最小,那麼我們的路徑從最左列到最右列,每一列的行號應該儘可能的小。根據我們目前已知的條件,我們可以在第一列中找出屬於最短路的最小行號(對應程式碼行31-34行)。至此我們得到正確路徑的開端。然後我們需要去找這條路徑上的對應下一列的行號。在這裡我們就需要另外一個二維陣列nexts(記錄當前路徑的下一個行號的最小值)。

如何確保是最小值?我們尋找當前狀態時是按順序尋找當前狀態的最小值的,因此得到的第一個狀態的最小值所對應的行號一定是我們所需要的最小行號。這裡特別要注意最後一行的下一行是第一行 這個條件,我起初是按照以下方式去執行三種決策(直行,右上,右下):

1                 for(int k = -1;k<=1;k++){
2                     if(cost[(j+k+r)%r][i+1] <t){
3                         nexts[j][i] = (j+k+r)%r;
4                         t = cost[(j+k+r)%r][i+1];
5                     }
6                 }

在一般情況下,這處程式碼不會有問題。可是一旦最短路從跨越了邊界,那麼行的訪問順序就變得無序了(如r-1,0,1),因此需要一次排序。

完整程式碼如下:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <climits>
 6 using namespace std;
 7 int cost[12][102];
 8 int C[12][102];
 9 int nexts[12][102];
10 int main(){
11     int r,c;
12     while(~scanf("%d%d",&r,&c)){
13         for(int i = 0; i < r; i++)
14             for(int j = 0; j < c; j++)
15                 scanf("%d",&C[i][j]);
16         for(int i = 0;i<r;i++)cost[i][c] = 0;
17         int first= 0,ans = INT_MAX;
18         for(int i = c-1;i >= 0;i--){
19             for(int j = 0; j < r; j++){
20                 int t = INT_MAX;
21                 int ks[] ={-1,0,1};
22                 ks[0]=(j-1+r)%r,ks[1]=(j+r)%r,ks[2]=(j+1+r)%r;
23                 sort(ks,ks+3);
24                 for(int k = 0;k<=2;k++){
25                     if(cost[ks[k]][i+1] < t){
26                         nexts[j][i] = ks[k];
27                         t = cost[ks[k]][i+1];
28                     }
29                 }
30                 cost[j][i] = t + C[j][i] ;
31                 if(i==0 && cost[j][i] < ans){
32                     ans = cost[j][i];
33                     first = j;
34                 }
35             }
36             
37         }
38         int minn = INT_MAX;
39         cout << first + 1 ;
40         for(int j = nexts[first][0],i=1; i < c;j=nexts[j][i],i++){
41             cout <<" "<< j + 1;
42         }
43         for(int i = 0;i<r;i++){
44             minn = min(minn,cost[i][0]);
45         }
46         cout  <<endl<< minn << endl;
47     }
48     return 0;
49 }

 

相關文章