【Ruby】【アルゴリズム】「開き直り数」を求める
今勉強している、この本↓にあった問題、「開き直り数」を求めました。
- 作者: 紀平拓男,春日伸弥
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2011/03/30
- メディア: 単行本
- 購入: 15人 クリック: 255回
- この商品を含むブログ (30件) を見る
問題
3435という数は、1桁ずつに分けて、それぞれの数を自分と同じ数でべき乗して足し合わせると,元の数である3435になる。
http://silver.arrow.jp/doc/puzzle/puzzle_cmag200106.php
3435 = 3**3 + 4**4 + 3**3 + 5**5
このような数を“開き直り数”と呼ぶことにする。ちょっと考えれば1(=11)もこの種の数であることがわかる。では1以上の整数で、この1と3435以外の開き直り数をすべて見つけていただきたい。ただし、ここでは00は0とする。
出来た!
書くのも早くなってきた!
解答
def hirakinaori?(candidate) result_digit = forDigit(total(candidate)) return true if candidate == result_digit return false end #[0,2,2,1,0,0,0,0,0,0] => 1**1*2 + 2**2*2 + 3**3*1 = 37 def total(arr) exponential = [0, 1, 4, 27, 256, 3125, 46656, 823543, 16777216, 387420489] result = 0 i = 0 while i < arr.length result += arr[i]*exponential[i] i += 1 end result end #12213 =>[0,2,2,1,0,0,0,0,0,0] def forDigit(int) tmp = int.to_s.split("").map!{|a| a.to_i} result = Array.new(10,0) tmp.each {|a| result[a] += 1 } result end def makeNumbers (result ,array, range_left, seed, count) return if count > 10 i = range_left while i < 10 tmp = array.dup tmp[i] += 1 result << tmp if hirakinaori?(tmp) makeNumbers(result, tmp, i, seed+1, count+1) i += 1 end result end init = Array.new(10,0) answer = makeNumbers([],init, 0, 1, 1) answer.delete([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) p answer answer.each {|arr| p total(arr)}
■実行結果
[[1, 0, 0, 1, 1, 1, 0, 1, 3, 1], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 2, 1, 1, 0, 0, 0, 0]] 438579088 1 3435
やった!