【题目链接】
ybt 2007:【20CSPJ普及组】方格取数
洛谷 P7074 [CSP-J2020] 方格取数
【题目考点】
1. 坐标型动规
【解题思路】
- 确定状态:a[i][j]为从起点走到i,j位置时整数和的最大值
- 确定状态转移方程:
- 熊从左上角出发,在第一列范围内只能向下走,可以求出第一列的状态。
- 从第一列某位置向右走到了第二列,不考虑走到第三列,在这一列中只能一直向上或下一个方向运动,因为不能重复经过已经走过的方格。
设一维数组u,d,
u[i]表示到第j列后只向上走,得到的i,j位置的状态a[i][j],
d[i]表示到第j列后只向下走,得到的i,j位置的状态a[i][j]。- 如果只考虑向上走,那么一个位置可能是从左侧或下侧走来的,取其中值更大的状态,u[i] = max(u[i+1], a[i][j-1])
- 如果只考虑向下走,那么一个位置可能是从左侧或上侧走来的,取其中值更大的状态,d[i] = max(d[i-1], a[i][j-1])
- 而后比较u[i]与d[i],取其中较大的值,作为a[i][j]。
【注意数据范围】:最大方格数有 1 0 3 ⋅ 1 0 3 = 1 0 6 10^3\cdot10^3 = 10^6 103⋅103=106个,每个格子最大值为 1 0 4 10^4 104,求出总和可能达到 1 0 10 10^{10} 1010,超出了int型表示的范围,因而要用long long类型。
【题解代码】
解法1:
#include<bits/stdc++.h>
using namespace std;
#define N 1005
long long mp[N][N], a[N][N], u[N], d[N];
int main()
{
int n, m;
cin>>n>>m;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
cin>>mp[i][j];
a[1][1] = mp[1][1];
for(int i = 2; i <= n; ++i)//求第一列的状态
a[i][1] = a[i-1][1] + mp[i][1];
for(int j = 2; j <= m; ++j)//遍历剩下各列
{
u[n] = a[n][j-1] + mp[n][j];//生成u数组,从下向上走,如果是最下面一行,只能从左走来。
for(int i = n - 1; i >= 1; --i)
u[i] = max(u[i+1], a[i][j-1]) + mp[i][j];//不是最下面一行,可能从左或下方来。
d[1] = a[1][j-1] + mp[1][j];//生成d数组,从上向下走,如果是最上面一行,只能从左走来
for(int i = 2; i <= n; ++i)
d[i] = max(d[i-1], a[i][j-1]) + mp[i][j];//不是最上面一行,可能从左或上方来。
for(int i = 1; i <= n; ++i)//生成a[i][j]
a[i][j] = max(u[i], d[i]);
}
cout<<a[n][m];
return 0;
}