Contest Hunter P5103 传纸条

目录:

  • 题目:
  • 分析:
  • 代码:


题目:

传送门


分析:

最暴力直接的方法就是四维dp,可小编看到书上有三维的,果断选了三维。但是,题目数据最大是到 50 50 ,可知道我把所有数组开到 100 100 AC A C ,硬生生恶心了我一个小时。
回到正题, f[i][x1][x2] f [ i ] [ x 1 ] [ x 2 ] 表示两条路径长度均为i,至于为什么不需要 y y ,这里就涉及到了一些些数学思维,思考一下就可以得到这个公式: x1+y1=x2+y2=i+2 x 1 + y 1 = x 2 + y 2 = i + 2 ,故此不需要 y y
至于dp的转移,也是十分直接,因为两个点都可以向右、向下移动,所以会有 22=4 2 ∗ 2 = 4 的情况,我们分开处理就好了


代码:

 #include
#include
#define LL long long
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
int max(int x,int y)
{
    return x>y? x:y;
}
int f[101][101][101];
int x[101][101];
int n,m;
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)
        x[i][j]=read();
    memset(f,-1,sizeof(f));
    f[0][1][1]=x[1][1];
    int y1,y2;
    for(int i=0;i2;i++)
    {
        for(int x1=1;x1<=n;x1++)
        {
           if(i+2-x1>m) continue;
           for(int x2=1;x2<=n;x2++)
           {
            if(f[i][x1][x2]==-1&&i+2-x2>m) continue;
            y1=i+2-x1;y2=i+2-x2;

            if(x1==x2) f[i+1][x1][x2]=max(f[i+1][x1][x2],f[i][x1][x2]+x[x1][y1+1]);
            else f[i+1][x1][x2]=max(f[i+1][x1][x2],f[i][x1][x2]+x[x1][y1+1]+x[x2][y2+1]);

            if(x1+1==x2+1) f[i+1][x1+1][x2+1]=max(f[i+1][x1+1][x2+1],f[i][x1][x2]+x[x1+1][y1]);
            else f[i+1][x1+1][x2+1]=max(f[i+1][x1+1][x2+1],f[i][x1][x2]+x[x1+1][y1]+x[x2+1][y2]);       

            if(x1+1==x2) f[i+1][x1+1][x2]=max(f[i+1][x1+1][x2],f[i][x1][x2]+x[x1+1][y1]);
            else f[i+1][x1+1][x2]=max(f[i+1][x1+1][x2],f[i][x1][x2]+x[x1+1][y1]+x[x2][y2+1]);

            if(x1==x2+1) f[i+1][x1][x2+1]=max(f[i+1][x1][x2+1],f[i][x1][x2]+x[x1][y1+1]);
            else f[i+1][x1][x2+1]=max(f[i+1][x1][x2+1],f[i][x1][x2]+x[x1][y1+1]+x[x2+1][y2]);       
           }
        }
    }
    printf("%d",f[n+m-2][n][n]);
    return 0;
}

你可能感兴趣的:(dp)