题面
分析
由于做过noip 2000 Day2 T6 方格取数
看到这道题的第一反映就是棋盘DP,
将方格取数的方程套用过来就有
f [ i ] [ j ] [ k ] [ l ] = m a x ( s i t i u a t i o n 1 , s i t i u a t i o n 2 ) + w f[i][j][k][l]=max(sitiuation1,sitiuation2)+w f[i][j][k][l]=max(sitiuation1,sitiuation2)+w
w = ( 第 一 个 人 和 第 二 个 人 在 同 一 位 置 ) ? G [ i ] [ j ] : G [ i ] [ j ] + G [ k ] [ l ] w=(第一个人和第二个人在同一位置)?G[i][j]:G[i][j]+G[k][l] w=(第一个人和第二个人在同一位置)?G[i][j]:G[i][j]+G[k][l]
s i t i u a t i o n 1 = m a x ( f [ i ] [ j − 1 ] [ k ] [ l − 1 ] , f [ i ] [ j − 1 ] [ k − 1 ] [ l ] ) sitiuation1=max(f[i][j-1][k][l-1],f[i][j-1][k-1][l]) sitiuation1=max(f[i][j−1][k][l−1],f[i][j−1][k−1][l])
s i t i u a t i o n 2 = m a x ( f [ i − 1 ] [ j ] [ k ] [ l − 1 ] , f [ i − 1 ] [ j ] [ k − 1 ] [ l ] ) sitiuation2=max(f[i-1][j][k][l-1],f[i-1][j][k-1][l]) sitiuation2=max(f[i−1][j][k][l−1],f[i−1][j][k−1][l])
这样子做的正确性就在于,一条从左上角到右下角的路线和另一条从右下角到左上角的路线严格不相交,其最大权值和,其实就等价于两条从左上角到右下角的严格不相交路线的最大权值和
只是这个严格不相交的实现是个麻烦点
但事实上只需要在枚举
l
l
l的时候将枚举起始点改为j+1即可
这样的话,就把第二个人可以行走的空间限制在了第一个人走的路线的右上方(图中),也就排除了相交的可能。并且由于第一个人行走的空间范围被枚举,于是限制
l
l
l也就不会使可能性减少
当然,由于第二个人的路线其实和第一个人的是等价的,于是最终状态就是
f
[
n
]
[
m
−
1
]
[
n
−
1
]
[
m
]
f[n][m-1][n-1][m]
f[n][m−1][n−1][m]
code
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(int i=start;i<=end;i++)
#define anti_loop(i,start,end) for(int i=start;i>=end;i--)
#define clean(arry,num); memset(arry,num,sizeof(arry));
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
#define ll long long
const int maxn=55;
const int maxm=55;
int n,m;
int f[maxn][maxm][maxn][maxm];
int g[maxn][maxm];
inline int read()
{
int neg=1;int ans=0;char r=getchar();
while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
while(r>='0'&&r<='9'){ans=ans*10+r-'0';r=getchar();}
return ans*neg;
}
int main()
{
//freopen("datain.txt","r",stdin);
n=read();m=read();clean(f,0);clean(g,-1);
loop(i,1,n)loop(j,1,m)g[i][j]=read();
loop(i,1,n)
{
loop(j,1,m)
{
loop(k,1,n)
{
loop(z,j+1,m)
{
f[i][j][k][z]=max(max(f[i-1][j][k-1][z],f[i-1][j][k][z-1]),max(f[i][j-1][k-1][z],f[i][j-1][k][z-1]))+g[i][j]+g[k][z];
}
}
}
}
printf("%d",f[n][m-1][n-1][m]);
return 0;
}
学到的东西
1.不要把方程打错了!!