题目链接:http://begin.lydsy.com/JudgeOnline/problem.php?id=2097
这题A的时候,百感交集五味杂陈。。。。。。。。。。。。
就这么一道看起来简单的不得了的裸的一件内衣都不剩的dp我就卡了几天
唉,看来我这种蒟蒻是没有救了。
看完题后,有些朋友可能会和我一样去定义一个数组f[i,j,l,r]表示第一个人在i,j位置,第二个人在l,r位置
然后一看n是小于等于100就放心大胆的继续码代码下去了
但实际上这东西如果单纯循环不仅仅会爆时间,还要爆内存(题坑)
这道题其实很简单,首先你画个图 可以发现,其实在每一步上,两个人的坐标和相等,而且坐标和是从2到n*2,刚刚好要走1到2*n-1步;
我们来写一下这个坐标和吧
2 3 4 5
3 4 5 6
4 5 6 7
5 6 7 8
好吧这就是坐标规律,及在第i步的时候我们应该在坐标和为i+1的点上 注:两人都在1,1这个起始点的时候我们就算成这是第一步
好了知道这个obvious的规律后,我们就可以简简单单的定义一个三维的数组了
我们定义f[k][i][j]表示在坐标和为k的位置上,第一个人的横坐标为i,第二个人的横坐标是j
(当然定义方式不止一种,我只是个人喜好这一种,另外一种定义是在第k步时,第一人的横坐标为i,第二人的横坐标为j)
定义出来了,这个状态转移就更简单了
我的定义对应的状态转移方程是:f[k][i][j]=max{f[k-1][i][j],f[k-1][i-1][j],f[k-1][i][j-1],f[k-1][i-1][j-1]}+abs(val[i][k-i]-val[j][k-j]);
然后我再提一下另一种方程的定义方案:f[k][i][j]=max{f[k-1][i][j],f[k-1][i-1][j],f[k-1][i][j-1],f[k-1][i-1][j-1]}+abs(val[i][k-i+1]-val[j][k-j+1]);
区别不大,只是在对应的纵坐标时有区别而已
然后这就是这道水出天际的题的解了
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #define maxn 105 8 using namespace std; 9 10 int n,val[maxn][maxn],f[maxn*2][maxn][maxn]; 11 12 int ma(int a,int b,int c,int d) 13 { 14 return max(max(a,b),max(c,d)); 15 } 16 17 int main() 18 { 19 scanf("%d",&n); 20 for(int i=1;i<=n;i++) 21 for(int j=1;j<=n;j++) 22 scanf("%d",&val[i][j]); 23 f[2][1][1]=0; 24 for(int k=3;k<=2*n;k++) 25 for(int i=1;i ) 26 for(int j=1;j ) 27 { 28 int iy=k-i,jy=k-j; 29 f[k][i][j]=ma(f[k-1][i-1][j-1],f[k-1][i-1][j],f[k-1][i][j-1],f[k-1][i][j])+abs(val[i][iy]-val[j][jy]); 30 } 31 printf("%d",f[2*n][n][n]); 32 33 }