数字三角形 的题目分原题(题目一)和变种(题目二),这里将两个题目都记在下面。

题目一

问题描述:

下图是一个数字三角形。 请编一个程序计算从顶至底的某处的一条路径,使该路径所经过的数字的总和最大。

  ●每一步可沿左斜线向下或右斜线向下走;

  ●1<三角形行数≤100;

  ●三角形中的数字为整数0,1,…99;

数字三角Python左对齐 python数字倒三角_python


输入格式:

文件中首先读到的是三角形的行数n。

接下来n行描述整个三角形

输出格式:

最大总和(整数)

样例输入:

5

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

样例输出:

30

这道题需要运用动态规划来进行解答,triL[ i ] [ j ]的值与其肩上两个数值(triL[ i -1] [ j -1]、triL[ i-1 ] [ j ])紧密相关,对每个triL[ i ][ j ],其值应为:triL[ i ][ j ]=triL[ i ][ j ]+max(triL[ i -1] [ j -1]+triL[ i-1 ] [ j ]),经过路径的最大总和,可以从上往下计算,也可以从下往上计算,其中从下往上计算,代码遍历的次数要少些。这里把两种代码附上:

从下往上:

n=int(input())
triL=[]
for i in range(n):
    triL.append(list(map(int,input().split())))

Sum=0
for i in range(n-2,-1,-1):
    for j in range(i+1):       
        triL[i][j]=triL[i][j]+max(triL[i+1][j],triL[i+1][j+1])
        if triL[i][j]>Sum:
            Sum=triL[i][j]
print(Sum)

遍历后再输出triL列表,结果如下:

数字三角Python左对齐 python数字倒三角_算法_02


可知最后一行数据其实是未被改动的。

从上往下:

n=int(input())
triL=[]
for i in range(n):
    triL.append(list(map(int,input().split())))

Sum=0
for i in range(n):
    for j in range(i+1):
        if i==0:
            continue
        if j==0:
            triL[i][j]=triL[i][j]+triL[i-1][0]
        elif j==i:
            triL[i][j]=triL[i][j]+triL[i-1][j-1]
        else:
            triL[i][j]=triL[i][j]+max(triL[i-1][j-1],triL[i-1][j])

print(max(triL[-1]))

遍历后再输出triL列表,结果如下:

数字三角Python左对齐 python数字倒三角_算法_03

题目二

2020年10月份的第十一届蓝桥杯省赛(第二场)也有道与之类似的题目,但题目多了条限制,即“向左下走的次数与向右下走的次数相差不能超过 1”。
这里把完整的题目附上。

问题描述:
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。
对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。
输入格式:
输入的第一行包含一个整数 N (1 < N ≤ 100),表示三角形的行数。下面的N 行给出数字三角形。数字三角形上的数都是 0 至 100 之间的整数。
输出格式:
输出一个整数,表示答案。
样例输入:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出:
27

开始的时候不知道如何对这个问题进行解答,后来在一篇博客里看到了作者的代码,作者的前面解题思路与上面所述的是一样的,即运用了动态规划,但在输出时进行了判断,按作者的思路,写出的代码如下:

n=int(input())
triL=[]
for i in range(n):
    triL.append(list(map(int,input().split())))

Sum=0
for i in range(n):
    for j in range(i+1):
        if i==0:
            continue
        if j==0:
            triL[i][j]=triL[i][j]+triL[i-1][0]
        elif j==i:
            triL[i][j]=triL[i][j]+triL[i-1][j-1]
        else:
            triL[i][j]=triL[i][j]+max(triL[i-1][j-1],triL[i-1][j])


lth=len(triL[-1])

if lth%2==0:
    print(triL[-1][lth//2-1])
else:
    print(triL[-1][lth//2])

由于题目要求“向左下走的次数与向右下走的次数相差不能超过 1”,因而存储最大和的元素绝不是最后一行的第一个和最后一个元素,但为何要取最后一行中间的元素 i ,以及为何当最后一行元素个数为偶数时,取 i-1 而不取 i+1,这个问题还没弄明白,先记在这里。