CH5103 传纸条

题意

描述

给定一个 N*M 的矩阵A,每个格子中有一个整数。现在需要找到两条从左上角 (1,1) 到右下角 (N,M) 的路径,路径上的每一步只能向右或向下走。路径经过的格子中的数会被取走。两条路径不能经过同一个格子。求取得的数之和最大是多少。N,M≤50。

输入格式

第一行有2个用空格隔开的整数n和m,表示有n行m列(1<=n,m<=50)。
接下来的n行是一个n*m的矩阵,每行的n个整数之间用空格隔开。

输出格式

一个整数,表示答案。

样例输入

3 3
0 3 9
2 8 5
5 7 0

样例输出

34

数据范围与约定

  • 30%的数据满足:1<=m,n<=10 
    100%的数据满足:1<=m,n<=50

来源

CCF NOIP2008 T3

分析

这种只能向右和向下走,只能在同时走到相同的格子,所以维护当前在哪个格子即可。容易设出状态\(F[x_1,y_1,x_2,y_2]\),但是这些状态并不都合法。只有\(x_1+y_1=x_2+y_2\)时状态才合法,这启示我们设立新的状态。

由于同一时间两条线路走的步数是相同的,而步数和行数就可以确定位置,所以可以用\(F[i,x_1,x_2]\)表示走了\(i\)步,第一条线走到了\(x_1\)行,第二条线走到了\(x_2\)行,已经取得的数的最大值。

那么枚举两条线路往哪走转移即可,注意判断走到了相同的格子。

时间复杂度\(O((n+m)n^2)\)

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;rg char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
    while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using std::max;

co int N=51;
int n,m,a[N][N],f[N*2][N][N];
int main(){
//  freopen(".in","r",stdin),freopen(".out","w",stdout);
    read(n),read(m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) read(a[i][j]);
    for(int i=0;i<n+m-2;++i)
        for(int j=1;j<=n&&j<=i+1;++j)
            for(int k=1;k<=n&&k<=i+1;++k){
                if(j==k){ // both right or down
                    f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]+a[j][i+3-j]);
                    f[i+1][j+1][k+1]=max(f[i+1][j+1][k+1],f[i][j][k]+a[j+1][i+2-j]);
                }
                else{
                    f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]+a[j][i+3-j]+a[k][i+3-k]);
                    f[i+1][j+1][k+1]=max(f[i+1][j+1][k+1],f[i][j][k]+a[j+1][i+2-j]+a[k+1][i+2-k]);
                }
                if(j+1==k) f[i+1][j+1][k]=max(f[i+1][j+1][k],f[i][j][k]+a[j+1][i+2-j]); // j down, k right
                else f[i+1][j+1][k]=max(f[i+1][j+1][k],f[i][j][k]+a[j+1][i+2-j]+a[k][i+3-k]);
                if(k+1==j) f[i+1][j][k+1]=max(f[i+1][j][k+1],f[i][j][k]+a[j][i+3-j]); // j right,k down
                else f[i+1][j][k+1]=max(f[i+1][j][k+1],f[i][j][k]+a[j][i+3-j]+a[k+1][i+2-k]);
            }
    printf("%d\n",f[n+m-2][n][n]);
    return 0;
}
上一篇:CH5202 自然数拆分Lunatic版


下一篇:CH5102 Mobile Service