动态规划 dp
方格取数类似于数字三角形,均可以使用动态规划直接秒杀.
但此题有 $3$ 个方向:上、右、下.所以可以定义一个三维数组 dp 数组.
假设 $f_{i, j, 1}$ 是从右、上方到达 $(i,j)$ 的和的最大值.
又有 $f_{i, j, 0}$ 是从右、下方到达 $(i,j)$ 的和的最大值.
我们可以先确定目标:$f_{n,m,1}$.为什么不是 $f_{n,m,0}$ 呢?因为小熊不可能从 $(n,m)$ 的下方到达终点.
状态转移
$f_{i,j,0} = max(f_{i+1,j,0}, max(f_{i,j-1,0}, f_{i,j-1,1})) + a_{i,j}$.
$f_{i,j,1} = max(f_{i-1,j,1}, max(f_{i,j-1,0}, f_{i,j-1,1})) + a_{i,j}$.
$a_{i,j}$ 表示当前各自的值.
当方向为 $0$ 时,说明小熊要往下方走,或者是右边走,但往右边走不管方向是 $0$ 或 $1$
均可以走.所以三者要取 $max$ 值.最后加上当前各自的值.
方向为 $1$ 时同理.
初始化
给 $f$ 数组中的格子赋一个较小的初值,类似于 $-10^{18}$.
然后将小熊的起点,即坐标 $(1,1)$ 的初值赋值如下:
f[1][1][0] = f[1][1][1] = a[1][1]
注意点
要开 long long!!!.
代码
这里使用类似于记忆化搜索的方式.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll min_ll = -1e18;
int n, m;
ll a[1005][1005], f[1005][1005][2];
ll dfs(int x, int y, int from) {
// 出界了
if (x < 1 || x > n || y < 1 || y > m) return min_ll;
// 有值了,返回
if (f[x][y][from] != min_ll) return f[x][y][from];
// 状态转移
if (from == 0) f[x][y][from] = max(dfs(x + 1, y, 0), max(dfs(x, y - 1, 0), dfs(x, y - 1, 1))) + a[x][y];
else f[x][y][from] = max(dfs(x - 1, y, 1), max(dfs(x, y - 1, 0), dfs(x, y - 1, 1))) + a[x][y];
return f[x][y][from]; // 希望得到的结果
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%lld", &a[i][j]);
f[i][j][0] = f[i][j][1] = min_ll; // 赋初值
}
}
f[1][1][0] = f[1][1][1] = a[1][1]; // 赋初值
printf("%lld", dfs(n, m, 1)); // 目标
return 0;
}
标签:int,题解,ll,dfs,取数,max,P7074,1005,include
From: https://www.cnblogs.com/panda-lyl/p/18498509