codeforces429B working out(dp)

来源:互联网 发布:网络教育文凭含金量 编辑:程序博客网 时间:2024/06/05 06:20

题目描述:
Working out
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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.

Examples
input
3 3
100 100 100
100 1 100
100 100 100
output
800
Note
Iahub will choose exercises a[1][1] → a[1][2] → a[2][2] → a[3][2] → a[3][3]. Iahubina will choose exercises a[3][1] → a[2][1] → a[2][2] → a[2][3] → a[1][3].

题目大意:
两个人,一个从左上角到右下角,每次只能向下走或者向右走,另外一个人从右上角到左下角,只能向下或者向左,使得两条线路做经过的数字的和最大(交叉点的数字两条路线都不算进去)

题目分析:
第一反应是搜索,因为每次选择只有两个,会选择让最后和最大的那个方向进行dfs,但是看了一下数据规模有1000,显然要搜的话得记忆话搜索,那么就变成了dp。最开始想的是循环扫描数组中的每一个点作为中间的交叉点,这样光循环就有10^6的复杂度,选中当前点作为中间的交叉点之后,在分别向4个角做dp,这样算下来复杂度为10^12,就抄了,所以换一个思路,把两个10^6相乘变成相加,从4个角分别向对角做dp,这样复杂度就是4*10^6=o(10^6),然后这样的话就可以得到每个点到4个角的最大值,接下来循环扫描每一个点作为交叉点,找出和最大的路径,但是到这里如果不加思考直接做的话就会出问题,因为对于不在边界上的任何一个点,从左上方来的话只能是从上方或者左方来,而从右上方来的话就会从这个点的上方和右方来,另外两个点也是如此,先分析这两个方向,他们有一个共同的来向,如果直接用当前点到4个角的最大值的和减去4倍的这个点的值,就有可能发生重叠,导致在这点之前路线就交叉了,显然不合题意,分析下来,交叉处只有两个选项,左上角的顶点从左方来,右下角的定点从右边来,或者是左上角的顶点从上方来,右下角的顶点从下方来,这是要注意的一个点,如果你分析了这一点的话,很容易知道边界点不可能是交叉点。

状态转移方程:(以从左上角开始的dp为例)dp[i][j]:表示从左上角到该位置路径的最大值
dp[i][j]=max(dp[i][j-1],dp[i-1][j]);

代码:

#include "stdio.h"#include "algorithm"using namespace std;typedef long long ll;ll dp1[1000+5][1000+5];ll dp2[1000+5][1000+5];ll dp3[1000+5][1000+5];ll dp4[1000+5][1000+5];int cal[1000+5][1000+5];int n,m;int main(){    int i,j;    while(scanf("%d%d",&n,&m)!=EOF)    {        for(i=1;i<=n;i++)        {            for(j=1;j<=m;j++)            {                scanf("%d",&cal[i][j]);            }        }        for(i=1;i<=n;i++)        {            for(j=1;j<=m;j++)            {                dp1[i][j]=max(dp1[i-1][j],dp1[i][j-1])+cal[i][j];            }        }        for(i=n;i>=1;i--)        {            for(j=1;j<=m;j++)            {                dp2[i][j]=max(dp2[i+1][j],dp2[i][j-1])+cal[i][j];            }        }        for(i=1;i<=n;i++)        {            for(j=m;j>=1;j--)            {                dp3[i][j]=max(dp3[i-1][j],dp3[i][j+1])+cal[i][j];            }        }        for(i=n;i>=1;i--)        {            for(j=m;j>=1;j--)            {                dp4[i][j]=max(dp4[i+1][j],dp4[i][j+1])+cal[i][j];            }        }                       ll mx=0,ca1,ca2;        for(i=2;i<n;i++)        {            for(j=2;j<m;j++)            {  //两种交叉方式,比较大小                ca1=dp1[i][j-1]+dp2[i+1][j]+dp3[i-1][j]+dp4[i][j+1];                ca2=dp1[i-1][j]+dp2[i][j-1]+dp3[i][j+1]+dp4[i+1][j];                mx=max(mx,max(ca1,ca2));            }        }        printf("%I64d\n",mx);    }    return 0;}
0 0
原创粉丝点击