I've been working on some Project Euler problems, and for the most part, I've been doing pretty well. Problem 18, though has really stumped me.
Starting at the top of a tree, I'm supposed to find the path that leads to the maximum sum
3
7 4
2 4 6
8 5 9 3
In this case, there are 24 possible paths, or 4! The best possible path is 3 -> 7 -> 4 -> 9 which sums up to 23.
I tried to solve the problem by replicating the example.
array = [[3],[7,4],[2,4,6],[8,5,9,3]]
array.each_slice(1){|s|p s} => This prints the tree
I got an answer which will on rare cases be correct, but it's not really legitimate.
sum = []
array.each{|a|sum.push(a.sample)}
return sum
This method is basically just selecting a random path and even with this easy example, there is still only a 1 in 24 chance of getting it right.
I've tried things like
level_two = []
level_three = []
for i in 0..array.length-1
for j in 0..array[1].length-1
level_two.push([array[0], array[1][i]) => Now level 2 has 2 paths - [3,7] & [3,4]
for k in 0..array[2].length-1
level_three.push([level_two[0],array[2][k], [level_two[1], array[2][k])
end
end
end
But at this point I can't even track which variables I'm using.
I've tried each_cons, combination and zip, none of which have worked.
Does anyone know of a strategy to solve this problem?
Edit: This won't give the answer to the problem, but simply the answer to the example. I will then apply that design pattern on the main problem.
This is how I would do it.
Code
Example
Thus, the longest path has length 23. From
3
in the first row, down and left (:l
) to7
in the second row, down and right (:r
) to4
in the third row and down and right to9
in the last row:3+7+4+9 => 23
.Explanation
This question is as much about the implementation of an algorithm as the choice of algorithm. It seems to me that the latter is fairly obvious: solve for one row, use that to solve for two rows, and so on.
Consider the example array
a
above.As
reduce
passes[h]
and[7, 4]
into the block and assigns the block variables:It then computes:
mid => []
becauseeach_cons(2)
is executed on an array of size 1.This last line above provides information for the longest paths to each of the two elements in the second row. For the first element (
7
), the path is of length10
and goes from the only element in the first row (3
) and then down and "left" (:l
) to the given element.As
[left, *mid, right]
is computed in the last row of thereduce
block, the block variablel
is given that value for the processing of the next row ofarr
:Next we compute the following:
The calculations of
left
andright
are similar to those done for the previous element ofarr
. Let's look at the calculation ofmid
:vals
is an array containing one element. That element is passed into themap
, decomposed and assigned to the block variables:As
10 > 7
, we execute:which is the value of
mid
. The block valuel
forreduce
is now assigned the result of[left, *mid, right]
:and processing of the third row commences.
reduce
returns:which provides information describing the longest path to each element of the last row. The last step is: