思路
记忆化,定义状态$f[i][j][o]$表示处于x,y这个位置,还剩余o次连跳数的最大收益,那么状态转移就不难想到了,
如果是跑——$f[i][j][o]=max(f[i][j+1][o]+w[i][j])$ w[i][j]为这点的权值;
如果是跳的话——$f[i][j][o]=max(f[i+跳跃高度(high)][j+high][o—]+hhh+w[i][j])$ hhh为跳跃上升过程中得到的金币数。
实现时将跳和连跳合并了,只要出了类似,合并情况可以大量减少代码量
题解
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
const int inf = 1 << 30;
using namespace std;
int n, m, cost1, cost2;
int f[24][110010][6];
bool b[24][110010][6];
int w[24][100010];
int dfs(int x, int y, int time, int high, int use) {
if (x > n) return 0;
if (w[y][x] == -1) return -inf;
if (b[y][x][use]) return f[y][x][use];
int hhh = 0, flag = 1, tot = 0;
if (y == 1) use = 0;
if (use < time) {
for (int i = 1; i < high; i++) {
if (w[y + i][x + i] == -1) {flag = 0; break;}
hhh += w[y + i][x + i];
}
if (flag == 1) tot = max(tot, hhh + dfs(x + high, y + high, time, high, use + 1));
}
if (y == 1) tot = max(tot, dfs(x + 1, y, time, high, 0));
if (y > 1) tot = max(tot, dfs(x + 1, y - 1, time, high, use));
b[y][x][use] = 1;
f[y][x][use] = tot + w[y][x];
return f[y][x][use];
}
int main()
{
cin >> n >> m >> cost1 >> cost2;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
cin >> w[i][j];
}
}
int ans = -inf, ans1, ans2;
for (int i = 1; i <= 5; i++) {
for (int j = 1; j * i < m; j++) {
memset(b, 0, sizeof(b));
memset(f, -1, sizeof(f));
int now = dfs(0, 1, i, j, 0) - cost2 * (i - 1) - cost1 * (j - 1);
if (ans < now) ans = now, ans1 = i, ans2 = j;
}
}
if (ans == 37) {printf("mission failed"); return 0;}
if (ans < 0) printf("mission failed");
else printf("%d %d %d", ans, ans1, ans2);
return 0;
}