程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> UVa 116 Unidirectional TSP (DP),unidirectionaltsp

UVa 116 Unidirectional TSP (DP),unidirectionaltsp

編輯:C++入門知識

UVa 116 Unidirectional TSP (DP),unidirectionaltsp


  該題是《算法競賽入門經典(第二版)》的一道例題,難度不算大。我先在沒看題解的情況下自己做了一遍,雖然最終通過了,思路與書上的也一樣。但比書上的代碼復雜了很多,可見自己對問題的處理還是有所欠缺。

  該題類似於數字三角形問題,處理的方式就是從倒數第二列逐步推到第一列, 每次選擇其後一列權值最小的那條路徑。最終找到花費最小的那個即可。由於出現多個答案時要輸出字典序考前的路徑,所以在選擇路徑的時候如果出現相同,要選擇行數小的那個。我在處理這個問題時用了很多條件語句,使得最終的代碼很長。下面是我的代碼:

  

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 using namespace std;
  6 
  7 long long a[12][110];
  8 int pre[12][110];
  9 
 10 int main()
 11 {
 12     int m, n, i, j,  temw, temr;
 13 
 14     while(scanf("%d%d", &m, &n) == 2)
 15     {
 16         for(i = 1; i <= m; i++)
 17         {
 18             for(j = 1; j <= n; j++)
 19             {
 20                 scanf("%lld", &a[i][j]);
 21             }
 22         }
 23         memset(pre, 0, sizeof(pre));
 24         for(j = n-1; j >= 1; j--)
 25         {
 26             for(i = 1; i <= m; i++)
 27             {
 28                 //首先考慮向上方向的路徑
 29                 if(i == 1)  //第一行,向上方向走到最後一行
 30                 {
 31                     temw = a[m][j + 1];
 32                     temr = m;
 33                 }
 34                 else
 35                 {
 36                     temw = a[i - 1][j + 1];
 37                     temr = i - 1;
 38                 }
 39                 //考慮向正前方向的路徑
 40                 if(a[i][j + 1] < temw)
 41                 {
 42                     temw = a[i][j + 1];
 43                     temr = i;
 44                 }
 45                 else if(a[i][j + 1] == temw)
 46                 {
 47                     temr = min(temr, i);  //相等取行號小的。
 48                 }
 49                 //考慮向下方向的路徑
 50                 if(i == m)  //最後一行,向下走到第一行
 51                 {
 52                     if(a[1][j + 1] < temw)
 53                     {
 54                         temw = a[1][j + 1];
 55                         temr = 1;
 56                     }
 57                     else if(a[1][j + 1] == temw)
 58                     {
 59                         temr = min(temr, 1);
 60                     }
 61                 }
 62                 else
 63                 {
 64                     if(a[i + 1][j + 1] < temw)
 65                     {
 66                         temw = a[i + 1][j + 1];
 67                         temr = i + 1;
 68                     }
 69                     else if(a[i + 1][j + 1] == temw)
 70                     {
 71                         temr = min(temr, i + 1);
 72                     }
 73                 }
 74                 a[i][j] += temw;
 75                 pre[i][j] = temr;  //記錄路徑
 76             }
 77         }
 78         temw = a[1][1];
 79         temr = 1;
 80         for(i = 2; i <= m; i++)  //尋找最小的。
 81         {
 82             if(a[i][1] <  temw)
 83             {
 84                 temw = a[i][1];
 85                 temr = i;
 86             }
 87         }
 88         //輸出路徑
 89         if(n == 1)
 90         {
 91             printf("%d\n", temr);
 92         }
 93         else
 94         {
 95             for(i = temr, j = 1; j <= n-1;)
 96             {
 97                 printf("%d ", i);
 98                 i = pre[i][j];
 99                 j++;
100             }
101             printf("%d\n", i);
102         }
103         printf("%lld\n", a[temr][1]);
104     }
105     return 0;
106 }

  顯然,在處理三個方向時,用了很多代碼,而書上是這樣做的:

  

 1 int rows[3] = {i, i-1, i+1};    //普通情況下的行號
 2 if(i == 0)  //書上第一行行號為0,如果是第一行,向上的行號需要改變。
 3     rows[1] = m - 1;  //最後一列列號為m-1
 4 if(i == m-1)
 5     rows[2] = 0;
 6 d[i][j] = INF;   //數組d用來存儲權值
 7 sort(rows, rows+3);   //先排序,再比較
 8 for(int k = 0; k < 3; k++)
 9 {
10     int v = d[rows[k]][j+1] + a[i][j];
11     if(v < d[i][j])
12     {
13         d[i][j] = v;
14         next[i][j] = rows[k];
15     }
16 }

  顯然,書上通過先排序再比較,這樣從最小的行號開始,找最小權值,找到的最小權值一定是行號最小的,減小了很多代碼量。

  還需要說的一點是,這道題我一開始看錯了題意!!!這是比賽的大忌! 根據所給的圖,想當然地以為是從第一行第一列開始走到最後一行最後一列。順便說一下這種情況的我的思路吧。這種情況下,需要一個bool型數組標記每個點是否可到達,首先標記終點可到達,然後從倒數第二列循環,選擇後一列中可以到達且權值最小,行號最小的一條路徑,並標記該點可到達,如果後面沒有可到達的點,就標記該點不可到達。循環到第一列時,只需要考慮起點即可。其他類似於原題。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved