一、 [USACO1.5] [IOI1994]数字三角形 Number Triangles
题目描述
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

在上面的样例中,从 7 → 3 → 8 → 7 → 5 7 \to 3 \to 8 \to 7 \to 5 7→3→8→7→5 的路径产生了最大权值。
输入格式
第一个行一个正整数 r r r ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
输出格式
单独的一行,包含那个可能得到的最大的和。
样例 #1
样例输入 #1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出 #1
30
提示
【数据范围】
对于 100 % 100\% 100% 的数据, 1 ≤ r ≤ 1000 1\le r \le 1000 1≤r≤1000,所有输入在 [ 0 , 100 ] [0,100] [0,100] 范围内。
题目翻译来自NOCOW。
USACO Training Section 1.5
IOI1994 Day1T1
二、思考
如下图:给出两幅图,你会想到什么解决办法呢?


错误思路
找到每行的最大值,依次向下查找
如果是按照这样的思路,会发现其他路径还有比当前路径之和大,代码运行失败!

思路分析
题意:从第一行的数开始,每次可以往左下或右下走一格,直到走到最下行,把沿途经过的数全部加起来。如何走才能使得这个和尽量大?
[分析]
如果熟悉回溯法,你可能会立刻发现这是一个动态的决策问题:每次有两种选择一一左下或右下。如果用回溯法求出所有可能的路线,就可以从中选出最优路线。但和往常一样,回溯法的效率太低:一个n层数字三角形的完整路线有 2”条,当n 很大时回溯法的速度将让人无法忍受。
为了得到高效的算法,需要用抽象的方法思考问题:把当前的位置(,看成一个状态(还记得吗?),然后定义状态(i的指标函 d(i,为从格子i,出发时能得的最大和(包括格子(G)本身的值)。在这个状态定义下,原问题的解是 d(1,1)。
下面看看不同状态之间是如何转移的。从格子(i,j)出发有两种决策。如果往左走,则走到(i+1,j)后需要求“从(i+1,j),出发后能得到的最大和”这一问题,即 d(i+1,j)。类似地,往右走之后需要求解 d(i11)。由于可以在这两个决策中自由选择,所以应选择 d(i+1,j)和d(i+1,j+1)中较大的一个。
换句话说,得到了所谓的状态转移方程:
d(i,j)=a(i,j)+max{d(i+l,j),d(i+l,j+I)}
如果往左走,那么最好情况等于(i,)格子里的值a(i,与“从(1出发的最大总和”之和,此时需注意这里的“最大”二字。如果连“从(+1.出发走到底部”这部分的和都不是最大的,加上 a(i,之后肯定也不是最大的。这个性质称为最优子结构 (optimalsubstructure),也可以描述成“全局最优解包含局部最优解”。不管怎样,状态和状态转移方程一起完整地描述了具体的算法。
回溯法

如图,构造初始的数字三角形

动态规划演示—从底端开始


最优解数字三角形构造完成,最优解为:30
此处回溯找出路径
从第一行开始,减去她它下一行左边或右边最优解的较大值,并从较大值开始往下求解

三、Code
C语言
//数字三角形--模板
#include <stdio.h>
int max(int a,int b) {
return a>b?a:b;
}

文章介绍了如何使用动态规划解决数字三角形问题,通过状态转移方程计算从顶到底部路径的和,避免了回溯法的低效。关键概念包括状态定义、状态转移方程和最优子结构。
最低0.47元/天 解锁文章
1114





