Pythonで「蓮と毛虫」ゲームの勝利に必要な期待手数を求めるプログラム
問題の概要
n行m列のグリッドを考えます。Amal(アマル)とBimal(ビマル)が、このグリッド上で次のようなルールのゲームを行います。
- Amalは白い「蓮(ロータス)」のタイルを最上行の任意のマスに置き、Bimalは「毛虫(キャタピラー)」のタイルを最下行の任意のマスに置きます。
- Amalが先手となり、交互に手番を進めていきます。
- Amalは自分のタイルを、現在いるマスに隣接する8方向(縦・横・斜め)のいずれかのマスへ移動できます。
- 一方、Bimalの毛虫タイルは、左右への移動またはその場にとどまることしかできません。
Amalの目的はできるだけ少ない手数でBimalを捕まえることであり、逆にBimalの目的はできるだけ長く逃げ続けることです。両者がそれぞれ配置する列をランダムに選んだ場合、Amalがこのゲームに勝つまでに必要となる手数の期待値を求めるのが本問題です。
例として、n = 5、m = 7 の場合、出力は 4.571428571428571 となります。
解法のアプローチ
この問題を解くには、以下の手順に従います。
- r を 0 で初期化します。
- l を 0 から m - 1 まで繰り返します。
- temp := n - 1.0 とします。
- l >= n の場合、temp に (l - n + 1) * ((l - 1) / m) を加算します。
- l < m - n の場合、temp に (m - n - l) * ((m - l - 2) / m) を加算します。
- r に temp / m を加算します。
- 最後に r を返します。
実装例
理解を深めるために、以下のPythonによる実装例を見てみましょう。
def solve(n, m):
r = 0
for l in range(m):
temp = n - 1.0
if l >= n:
temp += (l - n + 1) * ((l - 1) / m)
if l < m - n:
temp += (m - n - l) * ((m - l - 2) / m)
r += temp / m
return r
n = 5
m = 7
print(solve(n, m))
入力
5, 7
出力
4.571428571428571
-
Pythonでi個のx、j個のy、k個のzからなる部分列の個数を求めるプログラム
文字列 s が「x」「y」「z」で構成されているとします。このとき、「x」が i 個(i ≥ 1)、その後に「y」が j 個(j ≥ 1)、さらにその後に「z」が k 個(k ≥ 1)という順序で並ぶ部分列の総数を求めます。 例えば、入力が s = xxyz の場合、出力は 3 になります。これは xyz を2通りと xxyz を1通りの合計3通り作れるためです。 解き方のアプローチ この問題は動的計画法(DP)の考え方を使うと効率的に解けます。文字列を先頭から順に走査しながら、次の3つのカウンターを更新していきます。 x: それまでに見つかった「xのみで構成される部分列」の個数 y: そ
-
Pythonでソート済みリストの重複を削除するゲームに必要なターン数を求めるプログラム
問題の概要友人であるアマル(Amal)とビマル(Bimal)が、numsという名前のソート済み数値リストを使ってゲームを行っているとします。各ターンでは、まずアマルが任意の3つの数値を選び、次にビマルがそのうちの1つを削除し、続いてアマルがさらに1つを削除します。リストは最初、奇数個の要素で構成されています。ここで、アマルはリストから重複要素をなくすために必要なターン数を最小化したいと考え、一方ビマルはターン数を最大化しようとします。両者が最適な戦略で行動するとき、このゲームが完了するまでに必要なターン数を求めるのが課題です。入出力例例えば、入力が nums = [1, 1, 2, 3, 3,