四角递推(CF Working out,动态规划递推)

题目:假如有A,B两个人,在一个m*n的矩阵,然后A在(1,1),B在(m,1),A要走到(m,n),B要走到(1,n),两人走的过程中可以捡起格子上的数字,而且两人速度不一样,可以同时到一个点(哪怕这个点离A很近,离B很远),现在A,B起码相遇于一个点点,相遇点的数字A,B都得不到,求最后A,B总数字之和的最大值

B. Working out
Summer is coming! It's time for Iahub and Iahubina to work out, as they both want to look hot at the beach. The gym where they go is a matrix
a with n lines and
m columns. Let number
a[i][j] represents the calories burned by performing workout at the cell of gym in the
i-th line and the j-th column.
Iahub starts with workout located at line 1 and column
1. He needs to finish with workout
a[n][m]. After finishing workout
a[i][j], he can go to workout
a[i + 1][j] or a[i][j + 1]. Similarly, Iahubina starts with workout
a[n][1] and she needs to finish with workout
a[1][m]. After finishing workout from cell
a[i][j], she goes to either
a[i][j + 1] or
a[i - 1][j].
There is one additional condition for their training. They have to meet in exactly one cell of gym. At that cell, none of them will work out. They will talk about fast exponentiation (pretty odd small talk) and then both of them will move to the next workout.
If a workout was done by either Iahub or Iahubina, it counts as total gain. Please plan a workout for Iahub and Iahubina such as total gain to be as big as possible. Note, that Iahub and Iahubina can perform workouts with different speed, so the number of
 cells that they use to reach meet cell may differs.

Input
The first line of the input contains two integers n and
m (3 ≤ n, m ≤ 1000). Each of the next
n lines contains m integers:
j-th number from i-th line denotes element
a[i][j] (0 ≤ a[i][j] ≤ 105).

Output
The output contains a single number — the maximum total gain possible.

Sample test(s)

Input
3 3
100 100 100
100 1 100
100 100 100
 
Output
800
/*
思路:
要找最大值,那么只能有一个相遇点
如果用两个数组再来枚举相遇点是不可能的
所以比如说左上到右下,可以换成左上到相遇点,右下到相遇点
另一条路线也是如此

枚举各种可能的相交点,那么从左下角走到相交点或者从左上角走到
相交点的各种情况很容易用for写出来
可是从相交点到终点不好写,因为相交点是枚举的,
相当于未知,
逆向思维:从相交点到终点==从终点到相交点
而终点只有两个,递推就是要从已知到未知
那么这题就转换成从四个边角点到未知点
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn=1000+10;
ll f[maxn][maxn]={0},dp1[maxn][maxn],dp2[maxn][maxn],dp3[maxn][maxn],dp4[maxn][maxn];
int main()//定义数组f存基础数字,dp1代表从左上角递推
//dp2左下角,dp3右下角,dp4右上角
{
//输入环节
    ll m,n;
    cin>>m>>n;
    for(ll i=1;i<=m;i++)
        for(ll j=1;j<=n;j++)
        {
            scanf("%lld",&f[i][j]);
        }

//处理环节
    dp1[1][1]=f[1][1];//对dp1边缘赋值,即左边和上边两面墙赋入初始值
    for(ll i=2;i<=m;i++)
        dp1[i][1]+=f[i][1]+dp1[i-1][1];
    for(ll j=2;j<=n;j++)
        dp1[1][j]+=f[1][j]+dp1[1][j-1];

    dp2[m][1]=f[m][1];//对dp2边缘赋值
    for(ll i=m-1;i>=1;i--)
        dp2[i][1]+=f[i][1]+dp2[i+1][1];
    for(ll j=2;j<=n;j++)
        dp2[m][j]+=f[m][j]+dp2[m][j-1];

    dp4[1][n]=f[1][n];//对dp4边缘赋值
    for(ll i=2;i<=m;i++)
        dp4[i][n]+=f[i][n]+dp4[i-1][n];
    for(ll j=n-1;j>=1;j--)
        dp4[1][j]+=f[1][j]+dp4[1][j+1];

    dp3[m][n]=f[m][n];//对dp3边缘赋值
    for(ll i=m-1;i>=1;i--)
        dp3[i][n]+=f[i][n]+dp3[i+1][n];
    for(ll j=n-1;j>=1;j--)
        dp3[m][j]+=f[m][j]+dp3[m][j+1];

    for(ll i=2;i<=m;i++)//让i从2到m,j从2到n
        for(ll j=2;j<=n;j++)//下面再通过调一下下标与i,j的关系实现同时处理四个数组
        {
            dp1[i][j]+=f[i][j]+max(dp1[i-1][j],dp1[i][j-1]);
            dp4[i][n-j+1]+=f[i][n-j+1]+max(dp4[i][n-j+1+1],dp4[i-1][n-j+1]);
            dp2[m-i+1][j]+=f[m-i+1][j]+max(dp2[m-i+1+1][j],dp2[m-i+1][j+1]);
            dp3[m-i+1][n-j+1]+=f[m-i+1][n-j+1]+max(dp3[m-i+1+1][n-j+1],dp3[m-i+1+1][n-i+1+1]);
        }//dp1从左下角开始递推,dp2,3,4也从其他三个角开始递推
    ll ans=0;
    for(ll i=1;i<=m;i++)//这里两个for循环枚举相遇点
        for(ll j=1;j<=n;j++)
        {
            ans=max(ans,dp1[i][j]+dp2[i][j]+dp3[i][j]+dp4[i][j]-4*f[i][j]);
        }//如果[i][j]是相遇点,那么f[i][j]在dp1,dp2,dp3,dp4都被多拿了
        //(相遇点的数字不能拿,所以要减去4*f[i][j])
    cout<<ans<<endl;
    return 0;
/*********************这里预备一串代码输出dp1到dp4后来的具体情况
    可以自己用来检验dp1到dp4是否和自己想想的结果一样
    printf("\n");
    for(ll i=1;i<=m;i++)
        for(ll j=1;j<=n;j++)
    {
        printf("%lld ",dp1[i][j]);
        if(j==3)printf("\n");
    }
    printf("\n");
    for(ll i=1;i<=m;i++)
        for(ll j=1;j<=n;j++)
    {
        printf("%lld ",dp2[i][j]);
        if(j==3)printf("\n");
    }
    printf("\n");
    for(ll i=1;i<=m;i++)
        for(ll j=1;j<=n;j++)
    {
        printf("%lld ",dp3[i][j]);
        if(j==3)printf("\n");
    }printf("\n");
    for(ll i=1;i<=m;i++)
        for(ll j=1;j<=n;j++)
    {
        printf("%lld ",dp4[i][j]);
        if(j==3)printf("\n");
    }printf("\n");
************************/

}

猜你喜欢

转载自www.cnblogs.com/zyacmer/p/9912947.html
今日推荐