数字三角形——简单递推dp

    给定一个由 n n 行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形 的顶至底的一条路径(每一步可沿左斜线向下或右斜线向下),使该路径经过的数字总和最大

在这里插入图片描述

输入样例:

5 
7 
3 8 
8 1 0 
2 7 4 4
4 5 2 6 5 

输出样例:

30

    思路:很明显是用dp来解决,很容易启发对递归思想的理解
    既然要求第一层到最后一层的最长路径,那么肯定要遍历一遍,如果从 1 1 遍历到 n n dfs),每一层的最优情况我们都无从得知,因为后面的影响因素我们都无法预测,那么还有另一种方法:就是每一个点往下都只有两种情况,如果把这两种情况都记录下来,很明显最多有 2 n 2^n 种,非常复杂

    所以这里要换一种讨论最优解的思路,如果从第 n n 层遍历到第 1 1 层,那么我在遍历的时候,通过比较保存的值一定是从后往前的最优解!
    那么你可能会问,为什么从前往后不能保存最优解呢?因为从后往前是双入口单出口,这一个出口就保证了答案的唯一性
    而从前往后是单入口多出口,我们无法保证这多个出口哪一个才是最优解,如果直接将这两个出口进行比较,只能保证是局部最优,而不是全局最优

    换一种说法,从上到下的时候我们要把答案交给下一层解决、下一层不知道、只能交给下下一层解决 . . . . . . ...... ,直到最后一层
    而从下到上,我们已经知道了最后一层的解决办法,返回上一层,上一层得到解决,返回上上一层 . . . . . . ...... ,相当于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]);
}

猜你喜欢

转载自blog.csdn.net/Scar_Halo/article/details/83714806