在Python中完成欧拉计划第18题- 初学者

3

通过从下面的行中移动到相邻数字,从三角形顶部开始,最大的总和是23。

3
7 4
2 4 6
8 5 9 3

即,3 + 7 + 4 + 9 = 23。

在下面的三角形中找到从顶部到底部的最大总和:

75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23

注意:由于只有16384种路线,可以通过尝试每条路线来解决此问题。然而,第67个问题是同样具有一百行的三角形的挑战;它不能被蛮力解决,需要巧妙的方法!;o)

我的代码有点混乱

a="75, 95 64, 17 47 82, 18 35 87 10, 20 04 82 47 65, 19 01 23 75 03 34, 88 02 77 73 07 63 67, 99 65 04 28 06 16 70 92, 41 41 26 56 83 40 80 70 33, 41 48 72 33 47 32 37 16 94 29, 53 71 44 65 25 43 91 52 97 51 14, 70 11 33 28 77 73 17 78 39 68 17 57, 91 71 52 38 17 14 91 43 58 50 27 29 48, 63 66 04 68 89 53 67 30 73 16 69 87 40 31, 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23"
b=a.split(", ")
d=[]
ans=0
for x in range(len(b)):
    b[x]= b[x].split(" ")
    c= [int(i) for i in b[x]]
    d.append(c)
index= d[0].index(max(d[0]))
print index
for y in range(len(d)):
    ans+= d[y][index]
    if y+1==len(d):
        break
    else:
        index= d[y+1].index(max(d[y+1][index], d[y+1][index+1]))
print ans

我的答案是1063,而实际答案是1074。我猜测我的思路是正确的,但是还有一些错误我无法找到。


4
不,你的方法太贪心了,没有回溯。你总是选择立即的下一个最大值,但这并不一定会导致全局最大值。 - melpomene
2
似乎动态规划方法应该可行。 - John Coleman
(提示:您原则上可以用笔和纸解决这个问题;有一个线性算法。) - melpomene
@melpomene 也许我没有看到问题描述所暗示的巧妙方法,但我并不认为线性是可能的。另一方面,我也不确定它不可能。 - John Coleman
2
@JohnColeman 你不需要重复访问三角形中的任何数字。 - melpomene
@melpomene 好的。由于某种原因,我将您的评论解释为“与行数呈线性关系”。这是我的错误。 - John Coleman
5个回答

2

您的方法不正确。您不能只使用贪心算法。考虑以下示例:

3
7 4
2 4 6
8 5 9 500

显然:

3 + 7 + 4 + 9 = 23 < 500 + (other terms here)

你正在遵循这个算法。

然而,如果三角形只是:

3
7 4

贪心算法可行,换句话说,我们需要将问题简化为一种“三个数字”三角形。因此,假设您所遵循的路径到达 6,应该做出什么选择?前往 500。(如果路径到达 4 会发生什么?2呢?)
我们如何利用这些结果来制作一个更小的三角形?

1
看起来你总是选择下一行中更大的数字(左右两边),这被称为贪心算法。但也许首先选择较小的数字,你可以在随后的行中选择较大的数字。(事实上,通过这样做,可以达到1074。)
注释中的提示很有用:
- 回溯方法会给出正确的结果。 - 动态规划方法会给出正确的结果,并且比回溯更快,因此它也适用于问题67。

1

关于你的代码有一个小备注。 这个三角形中的最大和确实是1074。你的数字是正确的,只需要改变for循环的代码:

    for i,cell in enumerate(line):
    newline.append(int(cell)+max(map(int,topline[max([0,i-1]):min([len(line),i+2])])))

    for i,cell in enumerate(line):
    newline.append(int(cell)+max(map(int,topline[max([0,i-1]):min([len(line),i+1])])))

(“1”而不是“2”)

请注意

亲切地


0

你只能从顶部行相邻(最多)三个单元格中的每个单元格到达,其中最有利的是这些单元格中数字最高的一个,你不需要跟踪其他单元格。

我放了一份代码示例。这适用于左对齐的金字塔,就像你的问题一样(原始问题是带有居中的金字塔,但至少我没有完全破坏问题)。我的情况下最大总和为1116:

d="""
75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23
"""

ll=[line.split() for line in d.split('\n')][1:-1]
topline=ll[0]
for line in ll[1:]:
    newline=[]
    for i,cell in enumerate(line):
        newline.append(int(cell)+max(map(int,topline[max([0,i-1]):min([len(line),i+2])])))
    topline=newline
    print newline
print "final results is %i"%max(newline)

0

我整天晚上都在思考这个问题。这是我的解决方案:

# Maximum path sum I
import time
def e18():
    start = time.time()
    f=open("num_triangle.txt")
    summ=[75]
    for s in f:
        slst=s.split()
        lst=[int(item) for item in slst]
        for i in range(len(lst)):
            if i==0:
                lst[i]+=summ[i]
            elif i==len(lst)-1:
                lst[i]+=summ[i-1]
            elif (lst[i]+summ[i-1])>(lst[i]+summ[i]):
                lst[i]+=summ[i-1]
            else:
                lst[i]+=summ[i]
        summ=lst
    end = time.time() - start
    print("Runtime =", end)
    f.close()
    return max(summ)
print(e18()) #1074

附注:num_triangle.txt 文件中不包含第一个字符串“75”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接