题目来源:数字三角形
题目描述
给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。
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分析
- 状态表示:这是一类路线问题,可以用点的坐标表示(状态表示来源自经验),f[i][j]
1.1 集合:从底向上走到i ,j的所有路线的集合
1.2 属性:集合中的最大值 - 状态计算(对应集合划分 划分的一句是最后一个不同点 在这个问题中就是最后一步的走法)
f[i][j]怎么计算?按照我们的定义f[i][j]表示从底向上走到i ,j的所有路线的集合的最大值,题目中从底向上有n种方式,但是最后一步就是从(i+1,j)走上来,或者从(i+1,j+1)走上来。那么我们只要得走到(i+1,j)和(i+1,j+1)的最大值然后加上w[i][j]就好了,按照我们的定义,就得到了转移方程f[i][j]=max(f[i+1][j],f[i+1][j+1])+w[i][j]
代码
代码1
#include<bits/stdc++.h>
using namespace std;
const int N=510;
int n;
int w[N][N],f[N][N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
cin>>w[i][j];
//按照我们的定义 最后一层应该是不计算的
for(int j=1;j<=n;j++) f[n][j]=w[n][j];
//从倒数第二层开始计算
for(int i=n-1;i>0;i--)
for(int j=1;j<=i;j++)
f[i][j]=max(f[i+1][j],f[i+1][j+1])+w[i][j];
cout<<f[1][1]<<endl;
return 0;
}
代码2
去掉了w数组
#include<bits/stdc++.h>
using namespace std;
const int N=510;
int n;
int f[N][N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
cin>>f[i][j];
//从倒数第二层开始计算 最后一层不计算
for(int i=n-1;i>0;i--)
for(int j=1;j<=i;j++)
f[i][j]+=max(f[i+1][j],f[i+1][j+1]);
cout<<f[1][1]<<endl;
return 0;
}