您的位置:首页 > 其它

CF 429B. Working out DP

2016-07-26 10:43 411 查看

原题见CF 429B

给一个n*m的方格,A从左上角走到右下角,B从左下角走到右上角,路线交叉处的权值不算,问两条路线权值之和最大值。要求:两条路线只在一点交叉。

分析

可以枚举交叉点,求该点到四个角落的权值之和。到每个角的权值都可以dp得到最大值。从左上角顺时针得到0,1,2,3四个方向。

一开始没注意到题意里的只在一点交叉,妥妥跪了。

CF题解里的图片灰常清晰



两幅图的权值之和分别是:

dp[i][j-1][0] + dp[i-1][j][1] + dp[i][j+1][2] + dp[i+1][j][3]


dp[i][j-1][3] + dp[i-1][j][0] + dp[i][j+1][1] + dp[i+1][j][2]


还有需注意的是,交叉点只在(n-2)*(m-2)里面这个矩形里变化(否则一个角上的矩形会不存在)

代码

/*--------------------------------------------
* File Name: CF 429B
* Author: Danliwoo
* Mail: Danliwoo@outlook.com
* Created Time: 2016-07-26 10:41:26
--------------------------------------------*/

#include <bits/stdc++.h>
using namespace std;
#define N 1100
#define LL long long
int a

;
LL dp

[4];
int main(){
int n, m;
while(~scanf("%d%d", &n, &m)){
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
scanf("%d", &a[i][j]);
memset(dp, 0, sizeof(dp));
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
dp[i][j][0] = max(dp[i-1][j][0], dp[i][j-1][0]) + a[i][j];
for(int i = 1;i <= n;i++)
for(int j = m;j > 0;j--)
dp[i][j][1] = max(dp[i-1][j][1], dp[i][j+1][1]) + a[i][j];
for(int i = n;i > 0;i--)
for(int j = m;j > 0;j--)
dp[i][j][2] = max(dp[i+1][j][2], dp[i][j+1][2]) + a[i][j];
for(int i = n;i > 0;i--)
for(int j = 1;j <= m;j++)
dp[i][j][3] = max(dp[i+1][j][3], dp[i][j-1][3]) + a[i][j];
LL ans = 0;
for(int i = 2;i < n;i++)
for(int j = 2;j < m;j++){
ans = max(ans, dp[i][j-1][0] + dp[i-1][j][1] + dp[i][j+1][2] + dp[i+1][j][3]);
ans = max(ans, dp[i][j-1][3] + dp[i-1][j][0] + dp[i][j+1][1] + dp[i+1][j][2]);
}
printf("%I64d\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: