這裡要求要走到終點再走回來,可以轉化為兩個人走。
那麼我們可以先粗暴的設f[x1][y1][x2][y2]為第乙個人走到(x1, y1), 第二個人走到(x2, y2)的最大價值。
那麼這樣空間會很大,通過觀察可以發現,乙個走的步數=橫座標+縱座標,因為走一步一定是橫座標
或者縱座標+1.
那麼我們就可以轉化為f[step][x1][x2],可以退出y1 = step - x1, y2 = step - x2
那麼轉移方程就很好求了
f[step][x1][x2] = max(f[step-1][x1-1][x2], f[step-1][x1-1][x2-1], f[step-1][x1][x2-1], f[step-1][x1][x2]) + a[i][step-i]
+ (i == j ? 0 : a[j][step-j])
這裡要判斷如果是同乙個格仔的話只加一次。
實際這樣已經可以過了,**如下
#include#include#define rep(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;
const int maxn = 212;
int f[maxn*2][maxn][maxn];
int a[maxn][maxn], n, m;
void up(int& x, int a)
int main()
} printf("%d\n", f[n + m][n][n]);
return 0;
}
但是呢其實空間上還可以更優化,因為只和k-1有關
那麼我這裡想到兩種方法實現滾動陣列。
第乙個就是開兩個二維陣列,然後就來回更新。
#include#include#define rep(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;
const int maxn = 212;
int f[2][maxn][maxn];
int a[maxn][maxn], n, m;
void up(int& x, int a)
int main()
t ^= 1;
} printf("%d\n", f[t ^ 1][n][n]);
return 0;
}
還一種有點類似01揹包逆推那個做法,只用乙個陣列就可以實現,改變迴圈順序就好了。
為了讓當前狀態轉移的時候,用來更新的值都是上一行的,所以我們要逆序來操作。
因為如果是從上到下,從左到右的話,要更新當前狀態,需要用到f[i-1][j]等,而這個時候
f[i-1][j]之前已經算過了,已經更新過了,只要更新過了就成了這一行的值了,就不行。
所以我們要讓f[i-1][j], f[i-1][j-1], f[i][j-1],f[i][j]都沒有更新過。
所以我們就從下到上,從右到左來推,這樣就可以保證都是上一行的值了。
#include#include#define rep(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;
const int maxn = 212;
int f[maxn][maxn];
int a[maxn][maxn], n, m;
void up(int& x, int a)
int main()
} printf("%d\n", f[n][n]);
return 0;
}
51nod動態規劃 矩陣取數
乙個n n矩陣中有不同的正整數,經過這個格仔,就能獲得相應價值的獎勵,從左上走到右下,只能向下向右走,求能夠獲得的最大價值。例如 3 3的方格。1 3 3 2 1 3 2 2 1 能夠獲得的最大價值為 11。input 第1行 n,n為矩陣的大小。2 n 500 第2 n 1行 每行n個數,中間用空...
更難的矩陣取數問題
題目描述 乙個m n矩陣中有不同的正整數,經過這個格仔,就能獲得相應價值的獎勵,先從左上走到右下,再從右下走到左上。第1遍時只能向下和向右走,第2遍時只能向上和向左走。兩次如果經過同乙個格仔,則該格仔的獎勵只計算一次,求能夠獲得的最大價值。例如 3 3的方格。1 3 3 2 1 3 2 2 1 能夠...
dp 更難的矩陣取數問題
題目 乙個m n矩陣中有不同的正整數,經過這個格仔,就能獲得相應價值的獎勵,先從左上走到右下,再從右下走到左上。第1遍時只能向下和向右走,第2遍時只能向上和向左走。兩次如果經過同乙個格仔,則該格仔的獎勵只計算一次,求能夠獲得的最大價值。例如 3 3的方格。1 3 3 2 1 3 2 2 1 能夠獲得...