[noip模拟]散步<dp>

题目链接: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 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<cstdlib>
 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<k;i++)
26     for(int j=1;j<k;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 }
View Code
原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7537772.html