CF 429B B.Working out (四角dp)
阿新 • • 發佈:2018-09-28
size -- 動態規劃 最大 可能 ems std esp 。。
如果走的是臨邊,效果可能不一樣,可以試試。。。
題意:
兩個人一個從左上角一個從左下角分別開始走分別走向右下角和右上角,(矩陣每個格子有數)問到達終點後可以得到的最大數是多少,並且條件是他們兩個相遇的時候那個點的數不能算
思路:
首先這道題如果暴力搜索一般是gg了,所以考慮動態規劃
我們設起點為st(1,1),終點為ed(n,m),相遇的點為now(i,j)
問題轉化為計算st→now + now→ed
的值(不包含now)
這個問題可以分解為求st→now
和now→ed
的值,st→now = dp[st][now]
,那麽now→ed
怎麽求呢
可以反過來思考,now→ed
其實就是ed→now
的值,反向dp即可
還有個很重要的問題
在相遇的時候,即在點now時,每條路徑只能走相對的邊,如圖
如果走的是臨邊,效果可能不一樣,可以試試。。。
代碼:
#include<iostream> #include<cstring> #define max(a, b) ((a)>(b)?(a):(b)) using namespace std; typedef long long ll; const int maxn = 1010; int mp[maxn][maxn]; int dp1[maxn][maxn],dp2[maxn][maxn],dp3[maxn][maxn],dp4[maxn][maxn]; int main() { memset(dp1, 0, sizeof dp1); memset(dp2, 0, sizeof dp2); memset(dp3, 0, sizeof dp3); memset(dp4, 0, sizeof dp4); int n,m; scanf("%d %d", &n,&m); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { scanf("%d", &mp[i][j]); } } //從右下 走 for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { dp1[i][j] = max(dp1[i-1][j], dp1[i][j-1]) + mp[i][j];//到點(i,j)有兩種方法,以下如此 } } //從左上 走 for(int i = n; i >= 1; i--) { for(int j = m; j >= 1; j--) { dp2[i][j] = max(dp2[i+1][j], dp2[i][j+1]) + mp[i][j]; } } //從右上 走 for(int i = n; i >= 1; i--) { for(int j = 1; j <= m; j++) { dp3[i][j] = max(dp3[i+1][j], dp3[i][j-1]) + mp[i][j]; } } //從左下 走 for(int i = 1; i <= n; i++) { for(int j = m; j >= 1; j--) { dp4[i][j] = max(dp4[i-1][j], dp4[i][j+1]) + mp[i][j]; } } ll ans = -1; for(int i = 2; i < n; i++) { for(int j = 2; j < m; j++) { ans = max(dp1[i-1][j] + dp2[i+1][j] + dp3[i][j-1] + dp4[i][j+1], ans); ans = max(dp1[i][j-1] + dp2[i][j+1] + dp3[i+1][j] + dp4[i-1][j], ans); //把橫向穿過和縱向穿過,兩者進行枚舉 } } printf("%d\n", ans); return 0; }
CF 429B B.Working out (四角dp)