1. 程式人生 > >61計蒜客 動態規劃基礎 蒜頭君的城堡之旅

61計蒜客 動態規劃基礎 蒜頭君的城堡之旅

部分 pos include 路徑 entry 一個 空格 如果 size

蒜國地域是一個 n 行 m 列的矩陣,下標均從 1 開始。蒜國有個美麗的城堡,在坐標 (n,m) 上,蒜頭君在坐標 (1,1) 的位置上。蒜頭君打算出發去城堡遊玩,遊玩結束後返回到起點。在出發去城堡的路上,蒜頭君只會選擇往下或者往右走,而在返回的路上,蒜頭君只會選擇往上或者往左走,每次只能走一格。已知每個格子上都有一定數量的蒜味可樂,每個格子至多經過一次。 現在蒜頭君請你來幫他計算一下,如何計劃來回行程,可以收集到最多的蒜味可樂。

輸入格式

第一行輸入兩個整數 n,m(1≤n,m≤50),表示蒜國是一個 n 行 m 列的矩陣。 接下來輸入 n 行,每行輸入 m 個整數,代表一個 n×m 的矩陣,每個整數代表對應位置上的蒜味可樂數量,每行的每兩個整數之間用一個空格隔開。其中蒜頭君的位置和城堡的位置上沒有蒜味可樂,用 0 表示,其余位置上的整數範圍在 [1,100] 內。

輸出格式

輸出一行,輸出一個整數,表示蒜頭君在來回路上能收集到的蒜味可樂的最大值。

樣例輸入

3 3 0 2 9 4 8 6 2 7 0

樣例輸出

36

分析:

(可以理解為從起點出發的不相交的兩條路徑) 首先,要註意一個問題:不能先算出去的最大值,再算返回的最大值。這樣可能導致只保證了去的最大值,但沒有保證來回之和的最大值。也就是說,來回的優先級是相同的,但是如果先算去路的最大值就會使得去的優先級高於回的優先級。 容易註意到本題的範圍不大,所以可以用一個四維數組: f[i][j][k][l] 來表示路徑1走到 [i][j] 和路徑2走到 [k][l] 的和的最優值。 其中,因為走的步數相同,所以 i+j=k+l (可以利用這個等式來把空間和時間復雜度降一級),不難想到只要當前一步的兩條路徑沒有走到用一個點,兩條路徑就不會相交(如果相交,重疊部分的可樂只能領取一次,就不是最優情況)。 最後就不難寫出動規方程: f[i][j][k][l] = max(max(f[i-1][j][k-1][l], f[i][j-1][k-1][l]), max(f[i-1][j][k][l-1], f[i][j-1][k][l-1]))+map[i][j]+map[k][l]; 其中第一部分是求兩個路徑當前點的兩個前趨情況的和的最大值(一共是 2×2 四種情況,所以用了一個 max 套兩個 max)。 最最後,因為兩條路徑在終點還是會交於一點,所以千萬不能輸出 f[n][m][n][m] ,應該輸出 f[n-1][m][n][m-1] 。

標程:

技術分享圖片
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstring>
 4 using namespace std;
 5 int n,m,map[55][55],f[55][55][55][55];
 6 int main()
 7 {
 8     memset(f,0,sizeof(f));
 9     cin >> n >> m;
10     for (int i=1; i<=n; i++)
11     {
12         for (int j=1; j<=m; j++)
13         {
14             cin >> map[i][j];
15         }
16     }
17     for (int i=1; i<=n; i++)
18     {
19         for (int j=1; j<=m; j++)
20         {
21             for (int k=1; k<=n; k++)
22             {
23                 for (int l=1; l<=m; l++)
24                 {
25                     if (i+j!=k+l)
26                         continue;
27                     if (i==k && j==l)
28                         continue;
29                     f[i][j][k][l] = max(max(f[i-1][j][k-1][l], f[i][j-1][k-1][l]), max(f[i-1][j][k][l-1], f[i][j-1][k][l-1]))
30                     +map[i][j]+map[k][l];
31                 }
32             }
33         }
34     }
35     cout << f[n-1][m][n][m-1] << endl;
36     return 0;
37 }
技術分享圖片

61計蒜客 動態規劃基礎 蒜頭君的城堡之旅