Project Euler 67: Using an efficient algorithm find the maximal sum in the triangle?

Project Euler 67: Using an efficient algorithm find the maximal sum in the triangle?

Problem 67 of Project Euler feels a lot like cheating, since we have already solved the problem once in Problem 18

It is not even that I am clever to have seen the solution works for both problem, it is stated in the problem description which reads

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.

3
7 4
2 4 6
8 5 9 3

That is, 3 + 7 + 4 + 9 = 23.

Find the maximum total from top to bottom in triangle.txt, a 15K text file containing a triangle with one-hundred rows.

NOTE: This is a much more difficult version of Problem 18. It is not possible to try every route to solve this problem, as there are 299altogether! If you could check one trillion (1012) routes every second it would take over twenty billion years to check them all. There is an efficient algorithm to solve it. ;o)

However, I thought I would write a short post on it just because otherwise I feel I have a hole in the series. So in Problem 18 I described a solution based on dynamic programming which is the thing we need to use here.

I tried the brute force solution, but I gave up after 10 minutes believing that the twenty billion years in the problem description is probably right after all.

When using the dynamic programming solution we get a solution in 9ms including file access and what have you.

The largest sum through the triangle is: 7273
Solution took 9 ms

The image used in this post is attributed to Norm Walsh who kindly shared it under the creative commons license.

Posted by Kristian

11 comments

It’s amazing how a problem can be solved in 9ms instead of 20 billion years just be viewing it in another way.

Yes it does say a lot about the need to choose the right algorithm when approaching a problem. And it shows that even with faster computers we still need to think as programmers.

Nischay Nahata

Have a look at this brute force method (It tries all the possibilities) and gives the answer in 0.013s on my PC

import time
now = time.time()
n = []
for i in range(100):
	n.append(map(int,raw_input().split()))
newresult = [int(59)]
n.pop(0)
for i in range(99):
	x = n.pop(0)
	result = list(newresult)
	newresult =[]
	t = len(x)
	for j in range(t):
		if(j==0):
			newresult.append(result[0]+x.pop(0))
		elif(j==t-1):
			newresult.append(result[0]+x.pop(0))
		else:
			newresult.append(max((result.pop(0)+x[0]),result[0]+x.pop(0)))
print max(newresult)
print time.time()-now

As far as I can see from the code this is not a brute force solution where you check all 2^100 solutions, but rather a dynamic programming solution.

However, it seems nicely coded.

Nischay Nahata

Actually yes, its not a brute force because of the max() usage, but still I don’t think its dynamic. There is no reuse of any solution.

This was the first approach I came up and found others were using Trees and whatever and I don’t know what to call my solution (again I don’t think its dp)

Well the max statement is exactly what makes it dynamic programming.

I’ve created a Java object ‘tree’ and tought this problem would be a funny way to test it, so I added a recursive method that uses dynamic programming :



public int maxPath(){
		
		if(start.next==null)
			return (Integer)start.Object;
		return (Integer)start.Object+maxOf(new Tree(start.next.get(0)).maxPath(),new Tree(start.next.get(1)).maxPath());
	}

But this seems to be realy slow : I get the right solution in 30ms for problem 18 and I ran it for problem 67 15 minutes ago and still not getting any solution..

It seems to me that you don’t use dynamic programming, but rather does it the brute force way where you need to check each path. I might be completly wrong, but that it what it looks like to me.

Jean-Marie Hachey

Table 1 indicates that both plausible and optimal sums follow the same path up to EN 7 where 473 is reached. The gap between 390 and 473 is 83, a value absent from the data source; indeed, 38 is the alternative value to 80.

Table 1
Sum maximum for plausible and optimal path in the triangle
Re: Project Euler – Problem 67
http://img4.hostingpics.net/pics/932737pe67tableone.jpg
___

Table 2
Project Euler – Problem 67
Excerpt from Project Euler.net
http://projecteuler.net/project/triangle.txt

http://img4.hostingpics.net/pics/726431pe67table2.jpg

___

Sources:

1) Project Euler – Problem 67
Data source
http://projecteuler.net/project/triangle.txt
2) Project Euler – Problem 67
Kristian’s algorithm
http://www.mathblog.dk/files/euler/Problem18.cs
3) Microsoft Visual C# 2010 Express
4) Microsoft Office Excel (2007)

o0rebelious0o

I’ve managed it in 0.006 s in python using a bottom up dynamic programming solution. Haven’t posted the whole thing to stop people copying and pasting but should give the gist

def findMaxPath(self, i, j):
		if not self.maxPathFound[i][j] == -1:
			return self.maxPathFound[i][j]

		if i == len(self.pyramid) - 1:
			self.maxPathFound[i][j] = self.pyramid[i][j]
		else:
			self.maxPathFound[i][j] = self.pyramid[i][j] + max(self.findMaxPath(i+1, j), self.findMaxPath(i+1, j+1))

		return self.maxPathFound[i][j]

[…] more intuitive sense to solve the problem that way. You can check out some of those posts here and here if you are interested. I decided to solve the problem going from the top of the triangle downwards. […]

Leave a Reply