1. 程式人生 > >【洛谷】【動態規劃(多維)】P1006 傳紙條

【洛谷】【動態規劃(多維)】P1006 傳紙條

朋友 namespace PE n) 原來 這樣的 max 沒有 空間

【題目描述:】

小淵和小軒是好朋友也是同班同學,他們在一起總有談不完的話題。一次素質拓展活動中,班上同學安排做成一個m行n列的矩陣,而小淵和小軒被安排在矩陣對角線的兩端,因此,他們就無法直接交談了。幸運的是,他們可以通過傳紙條來進行交流。紙條要經由許多同學傳到對方手裏,小淵坐在矩陣的左上角,坐標(1,1),小軒坐在矩陣的右下角,坐標(m,n)。從小淵傳到小軒的紙條只可以向下或者向右傳遞,從小軒傳給小淵的紙條只可以向上或者向左傳遞。

在活動進行中,小淵希望給小軒傳遞一張紙條,同時希望小軒給他回復。班裏每個同學都可以幫他們傳遞,但只會幫他們一次,也就是說如果此人在小淵遞給小軒紙條的時候幫忙,那麽在小軒遞給小淵的時候就不會再幫忙。反之亦然。

還有一件事情需要註意,全班每個同學願意幫忙的好感度有高有低(註意:小淵和小軒的好心程度沒有定義,輸入時用0表示),可以用一個0-100的自然數來表示,數越大表示越好心。小淵和小軒希望盡可能找好心程度高的同學來幫忙傳紙條,即找到來回兩條傳遞路徑,使得這兩條路徑上同學的好心程度只和最大。現在,請你幫助小淵和小軒找到這樣的兩條路徑。

【輸入格式:】

輸入文件message.in的第一行有2個用空格隔開的整數m和n,表示班裏有m行n列(1<=m,n<=50)。

接下來的m行是一個m*n的矩陣,矩陣中第i行j列的整數表示坐在第i行j列的學生的好心程度。每行的n個整數之間用空格隔開。

【輸出格式:】

輸出文件message.out共一行,包含一個整數,表示來回兩條路上參與傳遞紙條的學生的好心程度之和的最大值。

技術分享圖片
輸入樣例#13 3
0 3 9
2 8 5
5 7 0
輸出樣例#134
輸入輸出樣例

[算法分析:]

f[i][j][k][l]表示小淵走到點(i, j)小軒走到點(k, l)時的最大好心度之和

a[i][j]表示點(i, j)上的同學的好心度

則狀態轉移方程為:

  f[i][j][k][l] = max{f[i - 1][j][k - 1][l], f[i - 1][j][k][l - 1], f[i][j - 1][k - 1][l], f[i][j - 1][k][l - 1]} + a[i][j] + a[k][l]

特判如果兩個點在一個點上就只加一個a[i][j].

時間復雜度為O(n2 * m2)(可以粗略地看成O(n4)

關於優化:

仔細思考後發現可以把四維壓到三維

此時f[i][j][k]表示小淵和小軒總共走了i步時小淵在第j行,小軒在第k

則此時小淵的坐標為(j, i - j),小軒的坐標為(k, i - k)

狀態轉移方程為:

  f[i][j][k] = max{f[i - 1][j - 1][k], f[i - 1][j][k - 1], f[i - 1][j][k], f[i - 1][j - 1][k - 1]} + a[j][i - j] + a[k][i - k]

註意此時f數組的第一維要開原來兩倍的空間,還要判斷列數合不合法.

時間復雜度O((n + m) * n2)(可以粗略地看成O(n3)

[Code:]

技術分享圖片
 1 //P1006傳紙條
 2 //688ms, 26.55MB
 3 #include<iostream>
 4 #include<cstdio>
 5 using namespace std;
 6 
 7 const int MAXN = 50 + 1;
 8 
 9 int n, m;
10 int a[MAXN][MAXN];
11 int f[MAXN][MAXN][MAXN][MAXN];
12 
13 inline int Max(int a, int b, int c, int d) { return max(max(max(a, b), c), d); }
14 
15 int main() {
16     scanf("%d%d", &n, &m);
17     for(int i=1; i<=n; ++i)
18         for(int j=1; j<=m; ++j)
19             scanf("%d", &a[i][j]);
20     for(int i=1; i<=n; ++i)
21     for(int j=1; j<=m; ++j)
22     for(int k=1; k<=n; ++k)
23     for(int l=1; l<=m; ++l) {
24         f[i][j][k][l] = Max(f[i-1][j][k-1][l], f[i-1][j][k][l-1], 
25                             f[i][j-1][k-1][l], f[i][j-1][k][l-1])+a[i][j]+a[k][l];
26         if(i==k && j==l) f[i][j][k][l] -= a[i][j];
27     }
28     printf("%d\n", f[n][m][n][m]);
29 }
未優化

技術分享圖片
 1 //P1006傳紙條
 2 //16ms, 3MB
 3 #include<iostream>
 4 #include<cstdio>
 5 using namespace std;
 6 
 7 const int MAXN = 50 + 1;
 8 
 9 int n, m;
10 int a[MAXN][MAXN];
11 int f[MAXN << 1][MAXN][MAXN];
12 
13 inline int Max(int a, int b, int c, int d) { return max(max(max(a, b), c), d); }
14 
15 int main() {
16     scanf("%d%d", &n, &m);
17     for(int i=1; i<=n; ++i)
18         for(int j=1; j<=m; ++j)
19             scanf("%d", &a[i][j]);
20     for(int i=1; i<=n+m; ++i)
21     for(int j=1; j<=n; ++j)
22     for(int k=1; k<=n; ++k) {
23         int x1 = j, y1 = i - j,
24             x2 = k, y2 = i - k;
25         if(y1<1 || y2<1) continue;
26         f[i][j][k] = Max(f[i-1][j-1][k], f[i-1][j][k-1],
27                          f[i-1][j][k], f[i-1][j-1][k-1])+a[x1][y1]+a[x2][y2];
28         if(x1==x2 && y1==y2) f[i][j][k] -= a[x1][y1];
29     }
30     printf("%d\n", f[n+m][n][n]);
31 }
降維優化

【洛谷】【動態規劃(多維)】P1006 傳紙條