とあるミッション(二日目)。

画像1

自然数 (1~18) をn個足して、合計がsになる組み合わせを全て用意する。
これ意外と難しいな。
試しに検索してみたら、それに近い命題のプログラムを作成する試験問題のようなページが見つかった。
それを見て驚く。
制限時間1分。なぬー! 1分でこの問題を解けってか? 考える暇などないではないか。プログラマってそんなに頭の回転が速くないと務まらないのか?
違った、secondは分じゃなくて秒だった。制限時間1秒。解けるわけないだろ! つまりコンピュータが1秒以内に答えられるアルゴリズムにしろってことか。ああびっくりした。
このくだりは残す意味あるかな?

例えば、n=3, s=7の場合ならどうか、パターンを洗い出してみる。

[5, 1, 1], [4, 2, 1], [3, 3, 1], [3, 2, 2]

あ、意外と少なく4通りしかない。
自然数がもし9以下なら、n桁の数字に見立てて各桁の合計がSになる数を拾い出せばいいかと思ったが、目の数は18までが条件。16進数も使えない。

見たところfor文を重ねて探し出せそうだが、重ねる回数nは不定なので、僕の認識だとこれは再帰処理になってしまう。
そして、パターンを抽出するプログラムがやっと完成した。たぶん回りくどいコードになっているんだろうなと思う。

def f(count, start):
   if count == n:
       answer.append([i for i in mine])
       return
   for i in range(start, 0, -1):
       if i * (n - count) + sum(mine) < s:
           return
       mine.append(i)
       f(count + 1, min(s - n - sum(mine) + count + 2, i))
       mine.pop()
   return

dice = [4, 2, 1] #相手のサイコロの目。面の数と合計値の条件が決まる
n = len(dice)
s = sum(dice)
mine = []
answer = []
f(0, max(dice) + 1)
print(answer)

相手に勝つためには、相手の目より一つでも大きければよい。相手のサイコロの目の最大値より2以上大きな数が含まれることは無意味と考え、最初から省いている。ここで
mine: サイコロの目のパターンのひとつ
count: 再帰処理の深さ=mineリストのインデックス
start: その数から降順に値を探す

さて、目のパターンが出来たら、相手の目との勝率を測る別の関数へとその都度飛ぶようにさせる。その最大のものをリストに残せばよい。
おや、思いのほか簡単に完成してしまった。

ところが、実行した結果CheckiOのサンプルテストの答とは微妙に違うものになった。勝率の測り方が間違っているらしい。

行き詰ってしまった。
(つづく)

この記事が気に入ったらサポートをしてみませんか?