题目描述:
Hello Kitty想摘点花生送给她喜欢的米老鼠。
她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。
地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。
Hello Kitty只能向东或向南走,不能向西或向北走。
问Hello Kitty最多能够摘到多少颗花生。
输入格式
第一行是一个整数T,代表一共有多少组数据。
接下来是T组数据。
每组数据的第一行是两个整数,分别代表花生苗的行数R和列数 C。
每组数据的接下来R行数据,从北向南依次描述每行花生苗的情况。每行数据有C个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目M。
输出格式
对每组输入数据,输出一行,内容为Hello Kitty能摘到得最多的花生颗数。
数据范围
1≤T≤100,
1≤R,C≤100,
0≤M≤1000
输入样例:
2
2 2
1 1
3 4
2 3
2 3 4
1 6 5
输出样例:
8
16
分析:
从本题起开始写算法提高课的题解了,首先是数字三角形模型,数字三角形问题见 AcWing 898 数字三角形。
题目要求从左上角出发,每次跨越向下或者向右走一步,最终到达右下角终点所有路径中摘得的最大花生数量。状态表示:f[i][j]表示从(1,1)出发走到(i,j)所有路径中摘得的最大花生数目。由于每次只能向下或者向右走,所以从(1,1)到(i,j)中所有路径中最后一步只可能是从(i-1,j)或者(i,j-1)走向(i,j)的,我们选择其中摘得花生数目较大的那个路径,再加上(i,j)格子上的花生数目就是从(1,1)走到(i,j)所有路径中可获得的最大花生数目了。因此易得状态转移方程为f[i][j] = max(f[i-1][j],f[i][j-1]) + w[i][j],其中w[i][j]表示(i,j)格子上的花生数目。
考虑到状态的无后效性,我们在计算f[i][j]时,需要确保之前的两个状态f[i-1][j]和f[i][j-1]均已经计算完毕了。即计算某个状态前,该状态左边和上边的状态均已计算完成,所以可以用自左而右,自上而下的遍历二维数组的方式来进行状态扩散。为了不特殊处理边界,可以默认f[i][0]和f[0][j]都是哨兵,方格中的边界状态从哨兵节点转移而来相当于之前未获得花生。由于读取花生的权值和状态的扩散顺序是一致的,所以可以在读取一行数据后立刻进行状态的计算。
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 105;
int w[N][N],f[N][N];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++){
scanf("%d",&w[i][j]);
f[i][j] = max(f[i-1][j],f[i][j-1])+w[i][j];
}
printf("%d\n",f[n][m]);
}
return 0;
}
上面代码之所以能够适用于多组测试用例,是因为每次处理不同的方格数据前,尽管f数组已经有了数据,但是所有哨兵的状态依旧是0,从而在状态扩散时可以替换掉旧的状态数据。当然,由于状态转移仅用到左边的和上一行的数据,所以也可以改成滚动数组实现的形式,即将f数组和w数组均改为一维的。计算f[j]时,用到了当前行最新的f[j-1]以及上一行还未替换的数据f[j],所以无须改变状态转移的方向。但是考虑到之前f[1][1]是由f[1][0]和f[0][1]这两个哨兵转移而来,所以多组数据的旧状态不会影响新的f数组,然而采用滚动数组后,f[1]是由f[0]和f[1]转移而来,而f[1]很可能还维持着上一组数据的计算状态,所以采用滚动数组实现计算完一组数据便需要清空f数组。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=105;
int w[N],f[N];
int main(){
int T;
scanf("%d", &T);
while(T--){
int n,m;
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d", &w[j]),f[j]=max(f[j],f[j-1])+w[j];
printf("%d\n", f[m]);
memset(f,0,sizeof f);
}
return 0;
}