给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输入格式
第一行包含整数n,表示数字三角形的层数。
接下来n行,每行包含若干整数,其中第 i 行表示数字三角形第 i 层包含的整数。
输出格式
输出一个整数,表示最大的路径数字和。
数据范围
1 ≤ n ≤ 500,
−10000 ≤ 三角形中的整数 ≤ 10000
输入样例
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出样例
30
这是一道非常经典的题目,从这道题目可以衍生出很多别的题型。这也是我们学习dp的一个入门题目。
题目分析:
dp问题要从状态表示(设定状态方程中每个数表示什么)和状态计算(状态方程是什么)两方面入手
- 状态表示:因为这道题要求的是到达底层的的最大路径数字之和。因此我们可以设出一个方程,求出走到每一个点的最大路径数字之和。这样状态就可以表示了
f[i][j] //表示从起点走到(i,j)的最大路径数组和
- 注:因为底层有n个数字,在求解答案时需要遍历底层的所有数,因此我们可以反过来进行求解,这样从底层走到最高层路径数字之和就一定为f[0][0] 。
- 状态计算:当要移动到(i,j)点时,它只能够从该点的左下或右下方移动过去,即从
f[i+1][j+1]和f[i+1][j]
移动过去。而f[i+1][j+1]和f[i+1][j]均为到达(i+1,j+1)和(i+1,j)的最大值,因此到达(i,j)的路径数字和的最大值只需要找到f[i+1][j+1]和f[i+1][j]的最大值即可。状态转移方程即为f[i][j]=max(f[i+1][j+1],f[i+1][j])+(i,j)点的数字
。
代码如下:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <iomanip>
#define LL long long
using namespace std;
const int N=505;
int main()
{
int n,f[N][N]={0};
cin>>n;
for(int i=0;i<n;i++) //初始化f[i][j],将(i,j)点的值提前保持在
for(int j=0;j<=i;j++) //f[i][j]中
cin>>f[i][j];
for(int i=n-2;i>=0;i--) //递推法从下往上找最大值
for(int j=0;j<=i;j++)
f[i][j]+=max(f[i+1][j+1],f[i+1][j]);
cout<<f[0][0]<<endl; //f[0][0]即为最大值
return 0;
}