# -*- coding: utf-8 -*- # http://odz.sakura.ne.jp/projecteuler/index.php?cmd=read&page=Problem%2061 # # まず4桁の三角数,四角数,五角数,六角数,七角数,八角数を全て生成する. # それらついて,先頭に0を含まない下位2桁と一致する先頭2桁を持つ数があれば # 下位→上位へ接続する. # 全て接続したら,全ての数を始点に6ステップで進める全ての経路を辿る. # 辿った経路上で,三角数,四角数,五角数,六角数,七角数,八角数がそれぞれ出現し, # 最後の数の下位2桁が,最初の数の上位2桁と一致するならば, # 問題の条件を満たしている順列となるので,各数の和を計算し,表示する. require 'set' # N角数 def pn(t, n) case t when 3 n * (n + 1) / 2 when 4 n * n when 5 n * (3 * n - 1) / 2 when 6 n * (2 * n - 1) when 7 n * (5 * n - 3) / 2 when 8 n * (3 * n - 2) end end # ノードの操作 @@nodes = {} def get_node(v) node = @@nodes[v] if (node) node else @@nodes[v] = {:nodes => Set.new, :type => v[:type], :n => v[:n]} end end def connect(v1, v2) e1 = get_node(v1) e1[:nodes] << v2 end # 6ステップで進める全ての経路を深さ優先探索する def dfs(v, ns = [], i = 0) if (i == 6) # 6ステップ進んで h = {} # 最後の数の下位2桁が,最初の数の上位2桁と一致して if (ns[0][:n] / 100 == ns[-1][:n] % 100 && # 経路上で,三角数,四角数,五角数,六角数,七角数,八角数がそれぞれ出現するならば ns.reduce({}) {|h, v| h[v[:type]] = true; h}.size == 6) # 答え ns.map{|n| n[:n]}.reduce(:+) else nil end else # 全ての経路について再起呼び出し v[:nodes].each do |v| if (ret = dfs(get_node(v), ns + [v], i + 1)) # 答えが出れば終わる return ret end end nil end end # N角数を1000個生成 data = 1000.times.map do |i| (3 .. 8).map do |t| {:type => t, :n => pn(t, i)} end end.flatten.select do |v| # 4桁のものでフィルタ 1000 < v[:n] && v[:n] < 10000 end # 4桁のN角数数について data.each do |v1| b1 = v1[:n].to_s[2, 2] # 先頭に0を含まない下位2桁と if (b1[0] != "0") data.each do |v2| a2 = v2[:n].to_s[0, 2] b2 = v2[:n].to_s[2, 2] # 上位2桁が一致する数があれば if (b2[0] != "0" && b1 == a2) # 接続 connect(v1, v2) end end end end # 4桁のN角数数について data.each do |v| # 6ステップで辿れる全ての経路を探索 if (ret = dfs(get_node(v))) # 答え puts ret break end end