Pythonで石取りゲームの勝者を求めるプログラムの書き方
問題の概要
Amal(アマル)とBimal(ビマル)がゲームをしていて、Amalが先手であるとします。このゲームは以下のようなルールです。
山の中にn個の石があります。各プレイヤーは順番に山から1個の石を取り、その石の位置に応じたポイントを受け取ります。ただし、AmalとBimalは同じ石を異なる価値で評価する場合があります。
同じ長さを持つ2つの配列 A_Values と B_Values が与えられます。A_Values[i] と B_Values[i] は、それぞれi番目の石に対するAmalとBimalの評価値を表します。すべての石が取り終わった時点で、合計スコアが高い方が勝者となります。スコアが同点の場合は引き分けです。両プレイヤーは最適な戦略でプレイし、互いの評価値も把握しているものとします。
結果として、Amalが勝てば1、Bimalが勝てば -1、引き分けなら0を返します。
入力例
A_Values = [2,4]、B_Values = [3,5] の場合、出力は1になります。これは、Amalが先に4ポイントの2番目の石を選ぶためです。するとBimalは残された3ポイントの1番目の石しか取れず、Amalのスコアの方が高くなるのでAmalの勝利となります。
解法のアプローチ
この問題を解くには、次の手順に従います。
- n を A_Values のサイズとする
- combinedValues という新しいリストを作成する
- i を0からn-1まで繰り返す
- tmpV := A_Values[i] + B_Values[i]
- ペア (tmpV, i) を combinedValues の末尾に追加する
- combinedValues を降順にソートする
- score_a := 0、score_b := 0 と初期化する
- i を0からn-1まで繰り返す
- curV := combinedValues[i]
- i が偶数(先手の番)の場合
- score_a := score_a + A_Values[curV[1]]
- それ以外(後手の番)の場合
- score_b := score_b + B_Values[curV[1]]
- score_a > score_b なら 1 を返す
- score_a == score_b なら 0 を返す
- それ以外は -1 を返す
なぜこの貪欲法が有効か
各石について「自分の評価値+相手の評価値」の合計を計算し、その合計値が大きい順に取っていくのが最適戦略です。ある石を取ることは、その石から得られる得点だけでなく、相手がその石から得られたはずの得点を奪うことにもなるため、両者の評価値の合計が大きい石ほど「取る価値」が高いと言えます。したがって、合計値の降順に交互に選択すれば、両者が最適にプレイした場合の結果を正しくシミュレートできます。
実装例
理解を深めるために、以下のPythonコードを見てみましょう。
def solve(A_Values, B_Values): n = len(A_Values) combinedValues = [] for i in range(n): tmpV = A_Values[i] + B_Values[i] combinedValues.append([tmpV, i]) combinedValues.sort(reverse=True) score_a, score_b = 0, 0 for i in range(n): curV = combinedValues[i] if (i % 2 == 0): score_a += A_Values[curV[1]] else: score_b += B_Values[curV[1]] if (score_a > score_b): return 1 elif (score_a == score_b): return 0 else: return -1 A_Values = [2,4] B_Values = [3,5] print(solve(A_Values, B_Values))
入力
[2,4], [3,5]
出力
1
-
Pythonでポリゴンの面積を求める方法:靴ひも公式を使った実装
はじめに2次元平面上に、単純な多角形(ポリゴン)の頂点を時計回りまたは反時計回りの順に並べた座標リストが与えられたとします。このとき、その多角形の面積を計算するのが本記事の目的です。例えば、入力が points = [(0, 0), (0, 5), (3, 5), (3, 0)] のような場合、これは幅3・高さ5の長方形を表しているため、出力は 15.0 となります。解法の考え方:靴ひも公式(Shoelace Formula)この問題は、有名な靴ひも公式(測量士の公式)を使うことで効率的に解けます。隣り合う2頂点ごとに外積 x1*y2 - y1*x2 を計算し、それらをすべて足し合わせて絶対値
-
Pythonで多角形の外周(周囲長)を求めるプログラム
問題の概要2次元平面上にある単純な多角形(自己交差しないポリゴン)の頂点が、順序付きの点のリストとして与えられているとします。このとき、その多角形の外周(周囲長)を求めることが目的です。例として、入力が points = [(0, 0), (0,5), (3, 5), (3,0)] の場合を考えてみましょう。このときの出力は 16 になります。これは、図からも分かるように、長さ3の辺が2本、長さ5の辺が2本存在するためです。したがって、2×5 + 2×3 = 16 となります。アルゴリズムの考え方この問題は、「隣接する2つの頂点間の距離をすべて計算して合計する」というシンプルなアプローチで解く