Pythonで解く数学パズル

「プログラマ脳を鍛える数学パズル」をPythonで解きます。

ルーレットの最大値:「プログラマ脳を鍛える数学パズル」Q10の答え

問題

この問題もCodeIQで見つからなかったので書籍版オリジナル問題と思われる。

ルーレットの目の配列にはヨーロピアンスタイルとアメリカンスタイルがある。連続するn個の目の和の最大値がヨーロピアンスタイル<アメリカンスタイルとなるような2以上36以下のnはいくつあるか?と言う問題。

わたしの考え方

  • 任意の目から順にn個のルーレットの目を合算する関数を定義する
  • n個の目の数の和の最大値を求める関数を定義する
  • さいごにヨーロピアンスタイルとアメリカンスタイルで比較する

わたしのオリジナル解答

European = [0,32,15,19,4,21,2,25,17,34,6,27,13,36,11,30,8,23,10,5,24,16,33,1,20,14,31,9,22,18,29,7,28,12,35,3,26]
American = [0,28,9,26,30,11,7,20,32,17,5,22,34,15,3,24,36,13,1,00,27,10,25,29,12,8,19,31,18,6,21,33,16,4,23,35,14,2]

def European_Sum(m, n):
    Sum = 0
    for s in range (m, m + n):
        if s >= 37:
            s -= 37
        Sum += European[s]
    return Sum

def European_Max(n):
    Max_sum = 0
    for m in range(0,37):
        if Max_sum < European_Sum(m, n):
            Max_sum = European_Sum(m, n)
    return Max_sum

def American_Sum(m, n):
    Sum = 0
    for s in range (m, m + n):
        if s >= 38:
            s -= 38
        Sum += American[s]
    return Sum

def American_Max(n):
    Max_sum = 0
    for m in range(0,38):
        if Max_sum < American_Sum(m, n):
            Max_sum = American_Sum(m, n)
    return Max_sum

cnt = 0
for n in range(2,36):
    if European_Max(n) < American_Max(n):
        cnt += 1
print cnt

模範解答のミソ

  • 模範解答ではn個の目の数の和の最大値を求める関数を直接定義している
  • どんな配列でも利用できるような汎用性の高いコードになっているので、コード自体がすっきりしている。

修正されたわたしの解答

European = [0,32,15,19,4,21,2,25,17,34,6,27,13,36,11,30,8,23,10,5,24,16,33,1,20,14,31,9,22,18,29,7,28,12,35,3,26]
American = [0,28,9,26,30,11,7,20,32,17,5,22,34,15,3,24,36,13,1,00,27,10,25,29,12,8,19,31,18,6,21,33,16,4,23,35,14,2]

def Sum_Max(roulette, n):
    Max_sum = 0
    for i in range(0,len(roulette)):
        Sum = 0
        for s in range(i, i + n):
            if s >= len(roulette):
                s -= len(roulette)
            Sum += roulette[s]
        if Max_sum < Sum:
            Max_sum = Sum
    return Max_sum

cnt = 0
for n in range(2,36):
    if Sum_Max(European, n) < Sum_Max(American, n):
        cnt += 1
print cnt

気づき・反省点

  • オリジナル解答ではn個の目の和を計算する関数と、和の最大値を求める関数を分けて書いたので冗長になっている。
  • さらにヨーロピアンスタイルとアメリカンスタイルも別々に書いたので4倍冗長。
  • 両者のスタイルで目の数が違う(ヨーロピアンは37、アメリカンは38)のだが、どんな場合でも対応できるような汎用性の高いコーディングを心がけるべき。

参考にしたサイト

ルーレット - Wikipedia