方格取数

方格取数

来源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]是从那里走过来的的呢,是从上面还是下面?

  1. 此时定义dp[x][y][fdir] 当fdir为0的时候表示肯定不从上面一格走到(x,y),反之亦然。

  2. 不管fdir=0还是=1,都有可能从左边一格更新,即向右走.

  3. 这种情况肯定无效 我走下去再走上来,或者我走上去再走下来

  4. 考虑左边一格的时候不知道是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

posted @ 2021-02-07 11:56  周昂没有周昂  阅读(105)  评论(0)    收藏  举报