VIJOS-P1474 雷曼兔(csapc)
JDOJ 1532: VIJOS-P1474 雷曼兔(csapc)
https://neooj.com/oldoj/problem.php?id=1532
Description
这次,OI山成为了雷曼兔那无尽的冒险传说的新舞台!传说OI山中埋藏着巨大的宝藏,伴随着这个传说的是一个迷题:最瑰丽的舞者将达至精灵世界的彼岸…… 经过仔细推敲,雷曼兔发现这是一个提示宝藏埋藏位置的谜语,在该谜语中指出了一个特定的路径,只有经过了该路径宝藏才会出现,具体情况如下: OI山的地势图可以看作一个N*N的数字矩阵,由1-N^2的数字组成(每个数字出现且仅出现一次),这些数字表示每个地点的地势高低。雷曼兔的出发点在最高的山顶处,并且每次雷曼兔可以从其当前所在的位置跳跃到任何一个比当前地点高度低的位置,假设雷曼兔该次跳跃从坐标(x1,y1)跳到了坐标(x2,y2),则这次跳跃的华丽度定义为v=(|x1-x2|+|y1-y2|)^2。而开启宝藏秘密的路径就是从山顶不断跳跃直到山底(高度最低点)的华丽度总和最高的路径,而现在我们想要知道的是这个最高的华丽度总和是多少
Input
第一行包括一个整数n(n< =50)表示地图的长宽。 接下来n行每行包括n个数表示每个地点的高度。
Output
输出包括一个整数ans,表示从山顶到山底最高华丽度总和
Sample Input
2 3 2 1 4
Sample Output
9
HINT
最优路径为4-> 3-> 2-> 1,得分为4+1+4=9。
这道题比线性动归稍微难了一点点。
难点在数据结构上。
可以开结构体,也可以二维数组,由于结构体码长比较恶心,所以我用的二维数组。
为什么呢?
因为算花费(华丽度)的时候要用到坐标,所以要把坐标和高度同时存进去。
一定要多开至少1位!别心疼那点空间,我就因为这个没A。
我们把状态设置成dp[i]表示从山脚跳到高度为i的点的华丽度的最大值。
然后还会有初始化的一个难点。
我们把初值设定为直接从i点跳到山脚的华丽度。
为什么呢?
因为我们状态的设定是反着来的。(从山脚往山顶蹦)
然后我们在动归松弛的时候就会发现,这其实和floyd的实现原理很像。
就是中间找断点看看能否松弛。
这也是一个很重要的思想
希望大家慢慢掌握
上代码:
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; int m[2600][3]; int n; int calc(int x,int y) { return (abs(m[x][1]-m[y][1])+abs(m[x][2]-m[y][2]))*(abs(m[x][1]-m[y][1])+abs(m[x][2]-m[y][2])); } int dp[2600]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { int a; scanf("%d",&a); m[a][0]=a; m[a][1]=i; m[a][2]=j; } for(int i=1;i<=n*n;i++) dp[i]=calc(i,1); for(int i=2;i<=n*n;i++) for(int j=1;j<i;j++) dp[i]=max(dp[i],dp[j]+calc(i,j)); printf("%d",dp[n*n]); return 0; }