さて
またまた東大の問題です。

確率を求めたりする計算は
プログラムの得意とするところで
業務でもよく出てきます。

いかに東大の問題と言えども
プログラミングができれば
簡単に解けてしまうと思います。

解説動画はこちら




2019年の問題

正八角形の頂点を反時計回りにA,B,C,D,E,F,G,Hとする。
また投げたときにおもて裏の出る確率がそれぞれ2分の1のコインがある。

点Pが最初に点Aにある。次の操作を10回繰り返す。
操作:コインを投げ表が出れば点Pを反時計回りに隣接する頂点に移動させ
裏が出れば点Pを時計回りに隣接する頂点に移動させる。
例えば点Pが点Hにある状態で、投げたコインの表が出れば点Aに移動させ
裏が出れば点Gに移動させる。

以下の事象を考える。

事象S:操作を10回行った後に点Pが点A上にある。
事象T:1回目から10回目の操作によって、点Pは少なくとも1回点Fに移動する。
(1)事象Sが起こる確率を求めよ
(2)事象Sと事象Tがともに起こる確率を求めよ


まずは問題文だけでは分かりづらいので
可視化してみましょう。

正8角形
反時計回りにA,B,C,D,E,F,G,H

この二つの条件で図形を描画してみます。

ライブラリを読み込んで
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure(figsize=(2,2),dpi=200)

r = 8
x = [np.sin(i) for i in np.linspace(0,2*np.pi,r+1)]
y = [np.cos(i) for i in np.linspace(0,2*np.pi,r+1)]
plt.plot(x,y)

t = ['A','H','G','F','E','D','C','B','']
for i ,(x1,y1) in enumerate(zip(x,y)):
    plt.text(x1,y1,t[i],ha='center',va='bottom')

plt.show()
8kakkei

このように描画できます。

x,yには正8角形の各x,yの座標

plt.plotではx,y座標を指定し
plt.textで図形に文字を付け加えられます。

生成した座標値は時計回りの座標なので
それを見越して表示させる文字を変えています。

それではイメージできたところで
問題を解いていきましょう。

1つめの問いは

(1)事象Sが起こる確率を求めよ
事象S:操作を10回行った後に点Pが点A上にある。 

まずは問題を解くのに必要なライブラリを読み込みます。
import itertools
from fractions import Fraction
coins = [i for i in itertools.product([1,-1],repeat=10)]
print(len(coins))

base = ['C','B','A','H','G','F','E','D','C','B','A','H','G','F','E','D','C','B','A','H','G’]
print(base[10])
1024
A

コインを10回ふった際の結果をcoinsという変数に格納します。

itertools.productで表裏の結果10回繰り返した際の順列が生成できます。
引数はその1回の組み合わせをリストで定義し
repeat=回数 で繰り返し回数が指定できます。

表は-1、裏は1として定義してrepaetが10回ですね。

単純に2の10乗回数だけコインをふることになりますね。

baseという変数にはAから始まって
時計回りに最大10回
反時計回りに最大10回
移動した際の点を入れます。
真ん中のbase[10]が開始地点です。


用意ができたらあとは計算だけですね。
10回ふった際の最終地点を求めて
その結果を辞書に格納してあげます。

最終地点:回数

とすることで確率が求められます。

calc_dict = {}
for coin in coins:
    key = base[10+sum(coin)]
    if key in calc_dict:
        calc_dict[key] +=1
    else:
        calc_dict[key] =1

for k,v in calc_dict.items():
    print(k,v)
C 256
A 272
E 240
G 256

print(calc_dict['A']/len(coins))
print(Fraction(calc_dict['A'],len(coins)))
0.265625
17/64

コインを10回ふった組み合わせ1024回のうち
Aに戻るのは272回でした。

なので確率としては
272/1064 

約分して
17/64となります。

Fractionで分数計算ができて
約分もしてくれます。

Pythonはこういうところが
めちゃくちゃ便利です。


2つめの問いは

(2)事象Sと事象Tがともに起こる確率を求めよ
事象S:操作を10回行った後に点Pが点A上にある。 
事象T:1回目から10回目の操作によって、点Pは少なくとも1回点Fに移動する。

条件が二つに増えます。

それではコインを10回ふった際の
軌跡を求めてみましょう。
coin_result = []
for coin in coins:
    tmp = 10
    result = ''
    for c in coin:
        tmp += c
        result += base[tmp]
    coin_result.append(result)

組み合わせの数だけ試行して
移動結果を文字としてつなげます。
リスト型に結果を保存します。

最終的に求める条件は
1.Fを通る(Fがある)
2.Aで終わる
この二つを満たす結果があれば
1カウントし、全組み合わせの中から
合致するものの個数を数えます。
count = 0
for row in coin_result:
    if 'F' in row and row[-1]=='A':
        count+=1
print(count)

66
print(count/len(coins))
print(Fraction(count,len(coins)))
0.064453125
33/512

最終的な答えの確率は
66/1024

約分して
33/512
となりました。

さていかがだったでしょうか?
確率を求めたりする計算は
日常業務ではよくでてきます。

数学的な可視化や
その計算については
numpyやmatplotlibライブラリを
用いることが多いです。

単純な計算については
通常のPythonプログラムだけでも
行うことができます。

問題を読み間違わなければ
このくらいの計算は
プログラミングで簡単に行うことができるので

プログラミングを覚えていない方
これから覚えたい方は
ぜひPythonを覚えてみてください。

Pythonについては無料の動画講座を用意しています。
乙py式5時間で学ぶプログラミング基礎(python編)

興味のある方はぜひこちらをご参照くださいませ。

それでは。