藍橋杯 算法訓練 ALGO-36 傳紙條


算法訓練 傳紙條  
時間限制:1.0s   內存限制:512.0MB
問題描述
  小淵和小軒是好朋友也是同班同學,他們在一起總有談不完的話題。一次素質拓展活動中,班上同學安排做成一個m行n列的矩陣,而小淵和小軒被安排在矩陣對角線的兩端,因此,他們就無法直接交談了。幸運的是,他們可以通過傳紙條來進行交流。紙條要經由許多同學傳到對方手里,小淵坐在矩陣的左上角,坐標(1,1),小軒坐在矩陣的右下角,坐標(m,n)。從小淵傳到小軒的紙條只可以向下或者向右傳遞,從小軒傳給小淵的紙條只可以向上或者向左傳遞。
  在活動進行中,小淵希望給小軒傳遞一張紙條,同時希望小軒給他回復。班里每個同學都可以幫他們傳遞,但只會幫他們一次,也就是說如果此人在小淵遞給小軒紙條的時候幫忙,那么在小軒遞給小淵的時候就不會再幫忙。反之亦然。
  還有一件事情需要注意,全班每個同學願意幫忙的好感度有高有低(注意:小淵和小軒的好心程度沒有定義,輸入時用0表示),可以用一個0-100的自然數來表示,數越大表示越好心。小淵和小軒希望盡可能找好心程度高的同學來幫忙傳紙條,即找到來回兩條傳遞路徑,使得這兩條路徑上同學的好心程度只和最大。現在,請你幫助小淵和小軒找到這樣的兩條路徑。
輸入格式
  輸入第一行有2個用空格隔開的整數m和n,表示班里有m行n列(1<=m,n<=50)。
  接下來的m行是一個m*n的矩陣,矩陣中第i行j列的整數表示坐在第i行j列的學生的好心程度。每行的n個整數之間用空格隔開。
輸出格式
  輸出一行,包含一個整數,表示來回兩條路上參與傳遞紙條的學生的好心程度之和的最大值。
樣例輸入
3 3
0 3 9
2 8 5
5 7 0
樣例輸出
34
數據規模和約定
  30%的數據滿足:1<= m, n<=10
  100%的數據滿足:1<= m, n<=50
 
題目解析:
  本道題需用到的算法為動態規划
  題目中提到在 m 行 n 列且帶有權值的矩陣中從(1,1)到(m,n)找一條路徑,然后再從(m,n)到(1,1)找一條路徑,這兩天路徑不能重復,即每個點只能兩個人只能走一次,且不可以回退,即第一條只能向下或向右,第二條只能向上或向左。化簡后可知:其實就是從(1,1)到(m,n)找兩條路徑,這兩條路徑只能向下或向右且不相交,計算出這兩條路徑的權值和的最大值即可。
  所以很容易構想出動態規划方程:
  兩個人走,利用四維的數組 dp[x1][y1][x2][y2] 來保存路徑中間過程的權值之和的最大值,其中 x1 y1 x2 y2 分別表示兩個人的位置。
  每個人現在的位置都有兩種可能:從他的上邊或左邊;兩個人組合就有四種可能,因此:構造出動態規划方程(map[x][y] 表示權值,即好心程度):
dp[x1][y1][x2][y2]=max(dp[x1-1][y1][x2-1][y2],dp[x1][y1-1][x2-1][y2],dp[x1][y1-1][x2][y2-1],dp[x1-1][y1][x2][y2-1])+map[x1][y1]+map[x2][y2];
  其中 x1,x2 的取值范圍為從起點到終點,即 1 ~ m,y1,y2 的取值范圍為起點到終點,即 1 ~ n。
  此方程的時間復雜度為 O(n4)。因此可以進一步優化:
  假如現在是 5 x 5 的矩陣,每個人從起點走三步,會出現四種情況。

  這四種情況的坐標分別為:(0,3)(1,2) (2,1) (3,0)。通過這四個坐標,發現一個規律: 0 + 3 = 1 + 2 = 2 + 1 = 3 + 0 = 3 = k (k為走的步數)。所有,x1 + x2 = k , x2 + y2 = k。所以,y = k - x。因此,三維的動態規划方程為:
dp[k][x1][x2]=max(dp[k-1][x1][x2],dp[k-1][x1-1][x2-1],dp[k-1][x1-1][x2],dp[k-1][x1][x2-1])+map[x1][k-x1]+map[x2][k-x2];
  其中,dp[k][x1][x2] 就是四維的 dp[x1][y1][x2][y2],dp[k-1][x1][x2] 就是四維的 dp[x1][y1-1][x2][y2-1],map[x1][k-x1] 就是四維的 map[x1][y1],以此類推。
  終點的坐標為 (m-1,n-1),但是 k 不能到達終點這個位置,因為違背了題目中兩個人不能重復,k 的最大情況為(m-1)+(n-1)- 1,k 在最小情況也就是 2 x 2 的矩陣中取得最小值 1,所以 k 的取值范圍為 1 ~   m+n-3。x1 和 x2  的取值范圍都為從起點(0,0)到最大步數 k,即 0 ~ k。
  此方程的時間復雜度為 O(n3)。因此還可以進一步優化:
  從三維的動態規划方程可以發現,前一步總是 k - 1,所以,二維的動態規划方程可以優化為:
dp[x1][x2] = max(dp[x1][x2], dp[x1 - 1][x2 - 1], dp[x1 - 1][x2], dp[x1][x2 - 1]) + map[x1][k - x1] + map[x2][k - x2];
  根據三維時的分析,兩條路徑都走不到終點,所以讓第一個人走到終點的上方,第二個人走到終點的左方,k 的取值范圍為 1 ~ (m-1)+(n-1)- 1,最終要輸出的結果為 dp[m-2][m-1]。
   此方程的時間復雜度為  O(n2)。
 
示例代碼1 [四維數組]:
 1 #include <iostream>
 2 #include<stdio.h>
 3 #include<cmath>
 4 using namespace std;
 5 
 6 #define MAX_NUM 52
 7 
 8 int map[MAX_NUM][MAX_NUM];     //好心程度 | 權值
 9 int dp[MAX_NUM][MAX_NUM][MAX_NUM][MAX_NUM];
10 
11 int maxPath(int m, int n)
12 {
13     for (int x1 = 1; x1 <= m; x1++)
14     {
15         for (int y1 = 1; y1 <= n; y1++)
16         {
17             for (int x2 = 1; x2 <= m; x2++)
18             {
19                 for (int y2 = 1; y2 <= n; y2++)
20                 {
21                     /*
22                         如果第一個人沒有走到最后一行或最后一列,並且兩個人沒有重復 
23                         因為走到最后一行或最后一列,容易造成第二個人無路可走的情況 
24                     */
25                     if ((x1 < m || y1 < n) && x1 == x2 && y1 == y2)     
26                     {
27                         continue;
28                     }
29                     dp[x1][y1][x2][y2] = max( max(dp[x1-1][y1][x2-1][y2], dp[x1-1][y1][x2][y2-1]), 
30                                               max(dp[x1][y1-1][x2-1][y2], dp[x1][y1-1][x2][y2-1]))
31                                              + map[x1][y1] + map[x2][y2];
32                 }
33             }
34         }
35     }
36     return dp[m][n][m][n]; 
37 }
38 
39 int main()
40 {
41     int m, n;
42     scanf("%d%d", &m, &n);
43     
44     for (int i = 1;i <= m; i++)
45         for (int j = 1;j <= n; j++)
46             scanf("%d", &map[i][j]);
47         
48     int ans = maxPath(m, n);
49     printf("%d\n", ans);
50         
51     return 0;
52 }
 
示例代碼2 [三維數組]:
 1 #include<iostream>
 2 #include<cstdio> 
 3 #include<cmath>
 4 using namespace std;
 5 
 6 #define MAX_NUM 52
 7 
 8 int map[MAX_NUM][MAX_NUM];     //好心程度 | 權值
 9 int dp[MAX_NUM+MAX_NUM][MAX_NUM][MAX_NUM];
10 
11 int maxPath(int m, int n)
12 {
13     for (int k = 1;k <= m+n-3; k++)
14     {
15         for (int x1 = 0; x1 <= k; x1++)
16         {
17             for (int x2 = 0; x2 <= k; x2++)
18             {
19                 if (x1 == x2)    //x1 == x2 相當於(x1 == x2 && y1 = y2) 
20                 {
21                     continue;
22                 }
23                 dp[k][x1][x2] = max(max(dp[k-1][x1][x2], dp[k-1][x1-1][x2-1]),
24                                     max(dp[k-1][x1-1][x2], dp[k-1][x1][x2-1]))
25                                 + map[x1][k-x1] + map[x2][k-x2];
26             }
27         }
28     }
29     return dp[m+n-3][m-1][m-2];
30 }
31 
32 int main()
33 {
34     int m, n;
35     scanf("%d%d", &m, &n);
36     
37     for (int i = 0; i < m; i++)
38         for (int j = 0; j < n; j++)
39             scanf("%d", &map[i][j]);
40             
41     int ans = maxPath(m, n);
42     printf("%d\n", ans);
43     
44     return 0;
45 }

 

示例代碼3 [二維數組]:
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string.h>
 4 #include<cmath> 
 5 using namespace std;
 6  
 7 #define MAX_NUM 52
 8 
 9 int map[MAX_NUM][MAX_NUM];   //好心程度 | 權值 
10 int dp[MAX_NUM][MAX_NUM];
11  
12 int maxPath(int m, int n)  
13 {  
14     memset(dp, 0, sizeof(dp));
15     for (int k = 1; k <= m+n-3; k++)  
16     {  
17         for (int x1 = m-1; x1 >= 0; x1--)  
18         {  
19             for (int x2 = m-1; x2 > x1; x2--)  
20             {  
21                 if ( k >= x1 && k >= x2)    //x + y = k,當k >= x時,說明還在矩陣范圍之內  
22                 {
23                     dp[x1][x2] = max(max(dp[x1][x2], dp[x1-1][x2-1]), 
24                                      max(dp[x1-1][x2], dp[x1][x2-1])) 
25                                  + map[x1][k-x1] + map[x2][k-x2];
26                 }
27             }  
28         }  
29     }  
30     return dp[m-2][m-1]; 
31 }
32   
33 int main()  
34 {
35     int m, n;
36     scanf("%d %d", &m, &n);
37       
38     for (int i = 0;i < m; i++)  
39         for (int j = 0; j < n; j++)  
40             scanf("%d", &map[i][j]);  
41     
42     int ans = maxPath(m, n);
43     printf("%d\n", ans); 
44     
45     return 0;  
46 }          
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM