Minstrel

Ruby, JavaScript, Haskell, Math, Music, Design

アルゴリズム問題: モンスターvsうさぎvs人間

TopCoderOpen 2008 Qual Round 1に出題されたEasy問題

いったいどこがEasyなんだ......

人間が1人、モンスターがM匹、ウサギがB匹います。ここから、モンスターか人間がいなくなるまで無作為に2匹(もしくは1人と1匹)を選び出し、以下の行動を繰り返します。

  • モンスターとモンスターが選ばれると、両方のモンスターが死にます
  • モンスターとモンスター以外が選ばれると、モンスター以外が殺されてしまいます
  • ウサギとウサギが選ばれると、何も起こりません
  • ウサギと人間が選ばれると、人間の生存確率が最も高くなるように、ウサギを殺す、またはそのままにする、のどちらかの選択をします

モンスターの数Mとウサギの数Bが与えられたときに、最後に人間が生き残る確率を答えなさい。ただし、M、Bともに1000以下の整数とする。

以下、ヒントと回答です。 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓

ヒント

①うさぎは実は考慮しなくていい。

②モンスターが奇数だったら...?

↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓

私の回答 by Ruby

MONSTER = ARGV[0].to_i
PERSON = 1

class Integer #Override
  # 5C2 = 10 みたいなやつ
  def c(m)
    (1..self).to_a.combination(m).to_a.length
  end
end

def recursive_battle(monster, result=1)
  return 0 if monster.odd? #偶数なら生存確率0%
  return result if monster <= 0 #基底部
  existence_this_time = existence(monster) #今回の生存確率を計算
  existence_total = result * existence_this_time #前回までの生存確率 * 今回の生存確率
  recursive_battle(monster - 2, existence_total) #Monsterの数を2匹減らして、再帰する。
end

def existence(monster)
  1.0 - (monster.to_f / (monster + 1).c(2).to_f )
end

puts recursive_battle(MONSTER, PERSON)

解説そのうち載せます。