Codeforces Round #245 (Div. 1) B. Working out

题目大意:

有一个人从左上角走到右下角,有一个人从左下角走到右上角。

两个人的路线只能有一个交点。每一个格子都有自己的值,走过这个路径就能获得对应的值。

规定两个人路线的交点的值两个人都不能获得。

求这两个人获得的值得最大值时多少

大致思路:

​ 首先先考虑简化的情况:只有一个人的时候,从左上走到右下角所能获得的最大值时多少?

​ 这个问题很显然的可以用DP去求,转移方程为:

\(dp[i][j] = max(dp[i-1][j],dp[i][j-1]) +g[i][j]\)

其中 \(g[i][j]\) 表示的是这个格子的值,\(dp[i][j]\) 表示的是走到 \(i\) 行,\(j\) 列时所能获得的最大收益。

​ 现在把之前的问题进行拓展,变成有两个人的时候,两个人所能获得的最大值是多少。(不考虑路径相交)

这个问题的解也很简单,和上面的一样列一个式子就可以了,不过转移需要稍微变化一下:

\(dp[i][j] = max(dp[i+1][j],dp[i][j-1]) +g[i][j]\)

现在把问题再拓展成题目中要求的情况。对于这个交点我们可以做出推断:

1.两个路径的交点一定是一个十字形状,且每一个人只能走直线。通过画图很容易就能得到。

2.交点的坐标不可能在边界上,通过画图也能很轻松的看出来。

于是我们可以尝试着去枚举这个交点,复杂度是 \(O(n^2)\) 的,很OK。

那么对于这个交点,我们需要知道两个人从出发点到这个点的最大值和从这个点分别到右下角与右上角的距离。

对于第一个问题,我们已经通过之前的两个dp式子得到。对于第二个问题,我们可以把实际情况倒过来考虑:

从交点分别到右下角和右上角的距离

变成

分别从右下角和右上角到交点的距离

问题一下子变得熟悉多了,就是之前推出来的那两个式子的变形。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e3+7;
ll dp1[maxn][maxn],dp2[maxn][maxn],dp3[maxn][maxn],dp4[maxn][maxn];
int g[maxn][maxn];
int main()
{
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    int n,m;
    ll ans=0;
    cin>>n>>m;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            cin>>g[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])+g[i][j];
    //左下
    for(int i=n;i>=1;--i)
        for(int j=1;j<=m;++j)
            dp2[i][j]=max(dp2[i+1][j],dp2[i][j-1])+g[i][j];
    //右上
    for(int i=1;i<=n;++i)
        for(int j=m;j>=1;--j)
            dp3[i][j]=max(dp3[i-1][j],dp3[i][j+1])+g[i][j];
    //右下
    for(int i=n;i>=1;--i)
        for(int j=m;j>=1;--j)
            dp4[i][j]=max(dp4[i+1][j],dp4[i][j+1])+g[i][j];
    for(int i=2;i<n;++i)
        for(int j=2;j<m;++j){//两种交叉情况,用笔画一画就明白了
            ll p1=dp1[i-1][j]+dp4[i+1][j];
            ll p2=dp2[i][j-1]+dp3[i][j+1];
            ans=max(ans,p1+p2);
            //cout<<"1 "<<i<<" "<<j<<" "<<p1<<" "<<p2<<endl;
            p1=dp1[i][j-1]+dp4[i][j+1];
            p2=dp2[i+1][j]+dp3[i-1][j];
            ans=max(ans,p1+p2);
           // cout<<"2 "<<i<<" "<<j<<" "<<p1<<" "<<p2<<endl;
        }
    cout<<ans<<endl;
    return 0;
}

posted @ 2018-06-07 20:44  SCaryon  阅读(155)  评论(0编辑  收藏  举报