Project Euler

Problem #61

Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:

Triangle   P_(3,n)=n(n+1)/2   1, 3, 6, 10, 15, ...
Square   P_(4,n)=n^(2)   1, 4, 9, 16, 25, ...
Pentagonal   P_(5,n)=n(3n−1)/2   1, 5, 12, 22, 35, ...
Hexagonal   P_(6,n)=n(2n−1)   1, 6, 15, 28, 45, ...
Heptagonal   P_(7,n)=n(5n−3)/2   1, 7, 18, 34, 55, ...
Octagonal   P_(8,n)=n(3n−2)   1, 8, 21, 40, 65, ...

The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three interesting properties.

  1. The set is cyclic, in that the last two digits of each number is the first two digits of the next number (including the last number with the first).
  2. Each polygonal type: triangle (P_(3,127)=8128), square (P_(4,91)=8281), and pentagonal (P_(5,44)=2882), is represented by a different number in the set.
  3. This is the only set of 4-digit numbers with this property.

Find the sum of the only ordered set of six cyclic 4-digit numbers for which each polygonal type: triangle, square, pentagonal, hexagonal, heptagonal, and octagonal, is represented by a different number in the set.

Ruby: Running time = 1.28s
+#triangles

+#squares

+#pentagonals

+#hexagonals

+#heptagonals

+#octagonals

+#Enumerable

def binary_interval(list,range)
  range=range.begin..(range.end-1) if range.exclude_end?
  i=list.length/2
end

def p61recur(so_far,available)
  return [so_far] if(available.length==0)
  res=[]
  available.each do |k|
    possible=$p61polys[k]
    possible=possible.select{|i|i/100==so_far.last%100} if so_far.length>0
    possible=possible.select{|i|i%100==so_far.first/100} if so_far.length==5
    new_res=possible.map{|p|p61recur(so_far+[p],available-[k])}
    res+=new_res.sum if new_res.length > 0
  end
  res
end

def p61
  $p61polys=Hash.new([])
  i=1
  i+=1 until octagonals(i) >= 1000
  while(triangles(i)<10000)
    v=[triangles(i),squares(i),pentagonals(i),hexagonals(i),heptagonals(i),octagonals(i)]
    (0...6).each{|j|$p61polys[j]+=[v[j]] if v[j].between?(1000,9999)}
    i+=1
  end
  puts p61recur([],(0...6).to_a).first.sum
end