【洛谷】【動態規劃(多維)】P1006 傳紙條
【題目描述:】
小淵和小軒是好朋友也是同班同學,他們在一起總有談不完的話題。一次素質拓展活動中,班上同學安排做成一個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共一行,包含一個整數,表示來回兩條路上參與傳遞紙條的學生的好心程度之和的最大值。
輸入樣例#1: 3 3 0 3 9 2 8 5 5 7 0 輸出樣例#1: 34輸入輸出樣例
[算法分析:]
設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 傳紙條