题意: 青蛙在起点0
,可以跳k
次,每次可以跳a~b
的距离,每跳到一个位置,都可以迟到该位置的昆虫,包括起始位置的昆虫。问青蛙最多可以吃到多少昆虫。
题解: 用DP,用搜索都可以解决这个问题,用搜索可能更加直观,从起点跳出去,通过BFS之后更新最大值,这几乎是没有异议的。
问题在于DP,题目当然是不难,我也很快写出一段代码,提交以后也AC了。
不严谨的代码(但能AC)
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int t, n, a, b, k;
int map[110], dp[110][110];
int main(){
scanf("%d", &t);
while(t--){
memset(dp, 0, sizeof dp);
scanf("%d%d%d%d", &n, &a, &b, &k);
for (int i = 1; i <= n; i++) scanf("%d", map + i);
for (int i = a; i <= n; i++)
for (int j = 1; j <= k; j++)
for (int l = a; l <= b; l++)
if(i-l > 0) dp[i][j] = max(dp[i][j], dp[i - l][j - 1] + map[i]);
printf("%d\n", dp[n][k] + map[1]);
}
return 0;
}
其状态转移方程为dp[i][j] = max(dp[i][j], dp[i - l][j - 1] + map[i]);
其中dp[i][j]表示 j 步到达位置 i 。但是但是但是,我发现了一个特殊样例:
1
8 1 1 2
1 2 3 4 5 6 7 8
用肉眼观察的话,我们很容易能看出,每次都只能跳一个单位,可以跳两次。也就是说我们的青蛙能吃到位置0、1、2上的昆虫,一共为6
,然而这段代码做出来,他选取了最后两个位置的昆虫,输出为16
.如果如果如果我的题目理解没有错的话,可能就是题目的测试数据不够严谨了。因为我的下一段代码,修改了这部分的“我认为的”错误,提交以后仍然AC。
修改后的代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int t, n, a, b, k;
int p[110], dp[110][110];
int main(){
scanf("%d", &t);
while(t--){
int ans = 0;
memset(dp, 0, sizeof dp);
scanf("%d%d%d%d", &n, &a, &b, &k);
for (int i = 0; i < n; i++) scanf("%d", p + i);
ans = dp[0][0] = p[0];
for (int i = 0; i < n; i++)
for (int j = 1; j <= k; j++)
for (int pos = i + a; pos <= i + b && pos < n; pos++){
if(dp[i][j - 1])
dp[pos][j] = max(dp[pos][j], dp[i][j - 1] + p[pos]);
ans = max(ans, dp[pos][j]);
}
printf("%d\n", ans);
}
return 0;
}