给定一个由 行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形 的顶至底的一条路径(每一步可沿左斜线向下或右斜线向下),使该路径经过的数字总和最大
输入样例:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出样例:
30
思路:很明显是用dp来解决,很容易启发对递归思想的理解
既然要求第一层到最后一层的最长路径,那么肯定要遍历一遍,如果从
遍历到
(dfs),每一层的最优情况我们都无从得知,因为后面的影响因素我们都无法预测,那么还有另一种方法:就是每一个点往下都只有两种情况,如果把这两种情况都记录下来,很明显最多有
种,非常复杂
所以这里要换一种讨论最优解的思路,如果从第
层遍历到第
层,那么我在遍历的时候,通过比较保存的值一定是从后往前的最优解!
那么你可能会问,为什么从前往后不能保存最优解呢?因为从后往前是双入口单出口,这一个出口就保证了答案的唯一性
而从前往后是单入口多出口,我们无法保证这多个出口哪一个才是最优解,如果直接将这两个出口进行比较,只能保证是局部最优,而不是全局最优
换一种说法,从上到下的时候我们要把答案交给下一层解决、下一层不知道、只能交给下下一层解决
,直到最后一层
而从下到上,我们已经知道了最后一层的解决办法,返回上一层,上一层得到解决,返回上上一层
,相当于dfs结束了返回的过程
这题是动态规划最水的一题大概,但是回过头来细细思考,还是温故而知新
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, a[105][105], dp[105][105];
int main(){
scanf("%d", &n);
for(int i=0; i<n; i++)
for(int j=0; j<=i; j++)
scanf("%d", &a[i][j]);
for(int i=0; i<n; i++) dp[n-1][i] = a[n-1][i];
for(int i=n-1; i>0; i--)
for(int j=0; j<i; j++){
dp[i-1][j] = max(dp[i-1][j], a[i-1][j] + dp[i][j]);
dp[i-1][j] = max(dp[i-1][j], a[i-1][j] + dp[i][j+1]);
}
printf("%d\n", dp[0][0]);
}