跳跃
C 跳跃
文件名 输入文件 输出文件 时间限制 空间限制
jump.cpp/c/pas jump.in jump.out 1s 512MB
题目描述
美丽国有 n 座小岛。这些小岛排成了一条直线,依次编号为 0,1,2,3... 有的小岛
上有金块,有的小岛上没有。美丽国有一个巨人 Bob,有一天他决定从第 0 个岛开
始,一直往后跳,看看自己能收集多少金块。
当然,Bob 不是没有目的性的乱跳;相反,Bob 的跳跃要满足以下规则:
• 首先 Bob 从 0 跳到 d 岛屿
• 假如 Bob 上一次跳了 l 步,则 Bob 下一次可以选择跳 l、l − 1、l + 1 步。注
意:所跳的步数不能小于 1,即如果上一次跳跃的步数为 1,下一次跳跃的步
数只能是 1 或者 2。
在这样的规则下,Bob 想知道,他最多能拿到多少金块?
输入格式
输入第一行两个整数 n,d,分别表示有金块的岛屿的个数,和 Bob 第一步要
跳的步数。
接下来 n 行,每行一个整数 id,表示编号为 id 的岛屿上有金块。
输出格式
输出仅一行,表示 Bob 最多能收集多少金块。
样例输入 1
4 10
10
21
27
27
6
样例输出 1
3
样例输入 2
8 8
9
19
28
36
45
55
66
78
样例输出 2
6
数据范围
对于 30% 的数据,1 ≤ n,d,id ≤ 100
对于 70% 的数据,1 ≤ n,d,id ≤ 1000
对于 100% 的数据,1 ≤ n,d,id ≤ 30000
我首先写了个记忆化搜索,想写dp但是不会写啊。
#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; int maxn; int n,d; int w[2009]; int ans; int f[1009][1009]; int dfs(int x,int tot,int last) { if(x>maxn) { ans=max(ans,tot); return tot; } if(f[x][last]) return f[x][last];//后面的都搜过就不搜了 for(int i=max(1,last-1);i<=last+1;i++) f[x][last]=max(f[x][last],dfs(x+i,tot+w[x+i],i)); return tot; } int main() { freopen("jump.in","r",stdin); freopen("jump.out","w",stdout); scanf("%d%d",&n,&d); for(int i=1,x;i<=n;i++) { scanf("%d",&x); w[x]++;maxn=max(maxn,x); } dfs(d,w[d],d); cout<<ans; return 0; }
dp从后向前搜,f[i][j]表示当前在位置i,接下来走j步,回溯回来能拿多少金币。
转移方程是
f[i][j]=a[i]+max(f[i+j][j],f[i+j][j+1],f[i+j][j-1]).
[#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; int maxn; int n,d; int w[2009]; int ans; int f[1009][1009]; int dfs(int x,int tot,int last) { if(x>maxn) { ans=max(ans,tot); return tot; } if(f[x][last]) return f[x][last]; for(int i=max(1,last-1);i<=last+1;i++) f[x][last]=max(f[x][last],dfs(x+i,tot+w[x+i],i)); return tot; } int main() { freopen("jump.in","r",stdin); freopen("jump.out","w",stdout); scanf("%d%d",&n,&d); for(int i=1,x;i<=n;i++) { scanf("%d",&x); w[x]++;maxn=max(maxn,x); } dfs(d,w[d],d); cout<<ans; return 0; }