数字三角形(最简单的DP,线性DP)
题目:
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和(路径上的每一步只可沿左斜线向下或右斜线向下走)。
输入描述
输入的第一行包含一个整数N (1≤N≤100),表示三角形的行数。
下面的 N 行给出数字三角形。数字三角形上的数都是 0 至 99 之间的整数。
输出描述
输出一个整数,表示答案。
输入输出样例
示例
输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出
30
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
思路:
首先,先思考一下,假如我们现在就在(i,j)这个位置,那我们下一步会往哪里走?
我们是不是下步要么往下,要么往右下?
也就是(i,j)=>(i+1 , j ) // ( i, j ) =>( i+1,j+1);
好的,现在再反推,(i,j)是从哪里来的捏?
可能是(i-1,j)或者(i-1,j-1),对吧?
我们定义一下,从(1,1)到(i,j)的过程中,经过的路程中数字的和最大的那个值为 f(i,j);
而这个题目就要求的是,从(1,1)到(n,j),j=1,2,3,……n
再假设(i,j)这个位置上的数是 a(i,j),那么,
这点的 f(i,j)=a(i,j)+max(f(i-1,j),f(i-1,j-1)),这个方程也叫动态转移方程式。
不过这个max(f(i-1,j),f(i-1,j-1))又是什么意思捏?
f(i-1,j)就是我们假设在(i-1,j)这个位置我们已经能够取到最大的和了
f(i-1,j-1)同理…
并且,我们在(i,j)又可能从上面这两个位置走来,可问题是我们不知道究竟从这两个那个位置走来才能让最后的结果最大呢?所以,我们就取他们中的最大值就好了
但是,对于我来说,你告诉了我,可以设f(i,j)就是到达了(i,j)这点可以得到的数字最大值和,我可能还是不太相信,为什么这样设了,然后结果就能真的得到最大值和呢?
那就找些简单的数来试一试吧!
假如输入样例长这样:
2
7
3 8
此时:
f(1,1)=max(f(0,1),f(0,0))+a(1,1)=0+7;
f(2,1)=max(f(1,1),f(1,0))+a(2,1)=7+3=10;
f(2,2)=max(f(1,1),f(1,2))+a(2,2)=7+8=15;
因为到达最后一行就停了,我们又不知道到达最后一行那个位置才最大,我们又会挨个分析每个位置
最后得出结果15;
好像的确可以做到,如果还是不信,还可以再多试几个样例
相关代码如下:
#include <iostream>
using namespace std;
const int N=101;
int dp[N][N],a[N][N],n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)//至于为啥是j<=i,因为它是三角形,不是矩形嘛!
cin>>a[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+a[i][j];
int maxy=dp[n][1];
for(int j=1;j<=n;j++)
maxy=max(dp[n][j],maxy);
cout<<maxy<<endl;
return 0;
}