方格取数
方格取数
来源CSP-J 2020 T4
题目描述
设有 n×m 的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中的整数,求它能取到的整数之和的最大值。
样例
输入
3 4
1 -1 3 2
2 -1 4 -1
-2 2 -3 -1
输出
9
解析
部分分
dfs+最优化剪枝(30?)
正解
考虑dp,dp[x][y]完全不够表示,如何知道dp[x][y]是从那里走过来的的呢,是从上面还是下面?
-
此时定义dp[x][y][fdir] 当fdir为0的时候表示肯定不从上面一格走到(x,y),反之亦然。
-
不管fdir=0还是=1,都有可能从左边一格更新,即向右走.
-
这种情况肯定无效 我走下去再走上来,或者我走上去再走下来
-
考虑左边一格的时候不知道是fdir=0大还是fdir=1大,因此仍需讨论
得出方程
dp[x][y][0]=max(dp[x+1][y][0],dp[x][y-1][0],dp[x][y-1][1])+a[x][y];
dp[x][y][1]=max(dp[x-1][y][1],dp[x][y-1][0],dp[x][y-1][1])+a[x][y];
为什么不需要讨论dp[x+1][y]或者dp[x-1][y]的fdir? (见3
上代码
#include <bits/stdc++.h>
using namespace std;
long long n, m, a[1000 + 10][1000 + 10];
long long dp[1000 + 10][1000 + 10][2];
// 0 = up , 1 = down , 2 =right
const int uinf = -0x7ffffff;
inline bool check(int x, int y) {
return x >= 1 && x <= n && y >= 1 && y <= m;
}
template <typename T> T m3x(T a, T b, T c) {
return max(max(a, b), max(b, c));
}
long long dfs(int x, int y, int fdir) {
if (check(x, y) == 0) return uinf;
if (dp[x][y][fdir] != uinf) return dp[x][y][fdir];
if (fdir == 0) {
return dp[x][y][0] = m3x(dfs(x + 1, y, 0), dfs(x, y - 1, 1), dfs(x, y - 1, 0)) + a[x][y];
}
else {
return dp[x][y][1] = m3x(dfs(x - 1, y, 1), dfs(x, y - 1, 0), dfs(x, y - 1, 1)) + a[x][y];
}
}
void in() {
scanf("%lld%lld", &n, &m);
for (int i = 1;i <= n;++i) {
for (int j = 1;j <= m;++j) {
scanf("%lld", &a[i][j]);
dp[i][j][0] = dp[i][j][1] = uinf;
}
}
}
int main() {
in();
dp[1][1][0] = dp[1][1][1] = a[1][1];
cout << dfs(n, m, 1); // 只需要fdir=1就行了,因为你不可能从终点下面一个走上来,那就越界了
}
ps:记得开long long

浙公网安备 33010602011771号