算法题(198):数字三角形
审题:
本题需要我们找到数字三角形中的最大路径总值,并输出思路:
方法一:动态规划由于本题的路径权值是路径上每一个值累加起来,问题具有阶段重复性,所以我们尝试使用动态规划解决此问题
(1)定义状态表示:f[i][j]表示从起点出发到(i,j)的最大权值
(2)求导状态转移方程:
我们先从最后一步开始分析,最后一步共有两条路线到达最后的节点,那么这两条路线中权值较大的那个路线+当前节点权值就等于结果权值即:f[i][j] = max(f[i-1][j-1],f[i-1][j]) + a[i][j]
(3)初始化
由于我们的f[i][j]计算依赖于f[i-1][j-1]和f[i-1][j],所以会有部分位置出现越界访问
图示:
左侧的所有节点都会出现越界访问情况
解决方法:从(1,1)开始记录数据与计算f数组
从(1,1)开始记录就不会出现越界访问的情况了,因为他们访问的就是外围的那一圈为0的值
第二个问题:如何确保不会将外围一圈的值当成较大权值路径去走?
我们先看数据范围,本题的数据值在0-100,所以我们初始化为0并不会让较大权值路径为外围一圈的节点。
如果题目的数据范围包含负数,那么我们就需要用最小的负数(-0x3f3f3f3f)来初始化所有值,以确保最大权值路径不会是不存在的那外围一圈
(4)填表顺序:从上至下
我们只要确保是从上到下进行计算就行,因为下一行的数据值是取决于上一行的数据值的
(5)输出答案
由于题目要求的是所有完整路径中的最大权值,所以我们最后还要遍历最后一行的所有f值,然后维护一个最大的值并输出
解题:
#include<iostream> using namespace std; const int N = 1010; int f[N][N];//f[i][j]表示从(1,1)走到(i,j)的最大累计权值 int r,a[N][N]; int main() {cin >> r;for (int i = 1; i <= r; i++){for (int j = 1; j <= i; j++){cin >> a[i][j];}}//状态转移方程使用for (int i = 1; i <= r; i++){for (int j = 1; j <= i; j++){f[i][j] = max(f[i - 1][j - 1], f[i - 1][j]) + a[i][j];}}//遍历最后一层的数据维护最终结果int ret = 0;for (int i = 1; i <= r; i++){ret = max(ret, f[r][i]);}cout << ret << endl;return 0; }
P1216 [IOI 1994] 数字三角形 Number Triangles - 洛谷