Python初級:スコアから金・銀・銅メダルを判定する2つのプログラムを解説
競技会などで「スコアに応じて金・銀・銅メダルを付与したい」とき、順位の付け方によって結果が変わることがあります。本記事では、Pythonで「順位ベース」と「スコアベース」2種類のメダル授与ルールを実装し、それぞれの違いをサンプルコードで解説します
問題
問題文
次のような問題を考えます。
与えられた参加者スコアのリストから、メダル授与の異なる2つのルールに基づいて、金・銀・銅メダルを獲得する参加者を決定してください。
🥇 ルール 1:順位ベースのメダル授与
1位に金メダル、2位に銀メダル、3位に銅メダルを付与します。ただし、同じスコアの人が複数人いる場合は、同順位とします。たとえば、100,100,90,80というスコアの場合、1位、1位、3位、4位とし、メダルは、金、金、銅、メダルなしとなります。
🥇 ルール 2:スコアベースのメダル授与
スコアが1位に金メダル、2位に銀メダル、3位に銅メダルを付与します。この場合は、100,100,90,80というスコアの場合、1位、1位、2位、3位とし、メダルは金、金、銀、銅となります。
入力は参加者のスコアリストです
20 30 40 50 60 20 30 90 100 90 90出力結果は、各参加者のメダルの色(GOLD, SILVER, BRONZE, 授与されない場合はNONE)とします。例の場合は、以下のようになります。
NONE
NONE
NONE
NONE
NONE
NONE
NONE
SILVER
GOLD
SILVER
SILVERルール1の解法
ルール1の解答は以下のようになります。
score = list(map(int, input().split()))
n = len(score)
persons = [(i, score[i]) for i in range(n)]
persons.sort(key=lambda x: x[1], reverse=True)
ans = [0 for _ in range(n)]
cur = persons[0][1]
num = 0
for i in range(n) :
if cur != persons[i][1] :
num = i
cur = persons[i][1]
ans[persons[i][0]] = num
for e in ans :
if e == 0 :
print("GOLD")
elif e == 1 :
print("SILVER")
elif e == 2 :
print("BRONZE")
else :
print("NONE")
入力処理
標準入力から、データの読み込みを行います。
score = list(map(int, input().split()))
n = len(score)input().split()で、スペース区切りのスコアを文字列リストとして読み込みます(例:'20 30 40' → ['20', '30', '40'])。※この時点では文字列ですmap(int, ...)で、文字列リストの要素全てを整数に変換しますlist(...)で、それを整数リストとしてscoreに格納しますn=len(score)で、参加者の人数を計算しています
データ整形
persons = [(i, score[i]) for i in range(n)]このまま score リストをソートしてしまうと、誰が何点だったのか(元の順番)がわからなくなってしまいます。そこで、(参加者番号(インデックス), スコア) というペア(タプル)のリスト persons を新しく作り、ソートしてもどの参加者のスコアだったかわかるようにしています。
score = [20, 100, 90] だった場合、 persons = [(0, 20), (1, 100), (2, 90)] となります
ソート
persons.sort(key=lambda x: x[1], reverse=True)persons リストをソートしています。key=lambda x: x[1] という指定は、「リストの各要素(x)の、2番目(インデックス 1)の値、つまりスコアを基準に並べ替えてください」という意味です。reverse=True は、降順(スコアが高い順)に並べ替える指定です。
persons = [(0, 20), (1, 100), (2, 90)] だった場合、 このブロック実行後は persons = [(1, 100), (2, 90), (0, 20)] となります。
順位決定
ans = [0 for _ in range(n)]
cur = persons[0][1]
num = 0
for i in range(n) :
if cur != persons[i][1] :
num = i
cur = persons[i][1]
ans[persons[i][0]] = numルール1(1位、1位、3位…)に従って、各参加者の順位を決定する処理のメインです。
ans = [0 for _ in range(n)]:
結果を「元の入力順」で格納するためのリストを、一旦0で初期化して用意しますcur = persons[0][1]curは、現在の最上位のスコアです。ソート後のリストの先頭(最高得点)で初期化することで、一番高いスコアに初期化されますnum = 0
現在の順位(num)を0(=1位)で初期化しますfor i in range(n)
ソート済みのpersonsリストを上から(高得点者から)順番に見るループですif cur != persons[i][1]
もし、前の人のスコア(cur)と今の人のスコア(persons[i][1])が違っていたら、 順位(num)を、現在のループインデックスiで更新します。 インデックスiは、順位(0インデックス)の値と同じなので、スコアが変わったら順位を合わせて更新する処理になります。
cur = persons[i][1]curを今の人のスコアで更新し、次のループに備えます。ans[persons[i][0]] = numpersons[i][0]で「参加者の番号」を取り出し、ansリストの参加者の位置に、決定した順位numを格納します。
これで、ansには各参加者の順位(0位から〜)が格納されます。
出力処理
for e in ans :
if e == 0 :
print("GOLD")
elif e == 1 :
print("SILVER")
elif e == 2 :
print("BRONZE")
else :
print("NONE")
順位が「元の入力順」で格納された ans リストを、先頭から順に見ていき、0ならGOLD, 1ならSILVER, 2ならBRONZE, それ以外の場合はNONEを表示します。
以上がプログラムの処理になります。
ルール2の解法
ルール2の解答は以下のようになります。
score = list(map(int, input().split()))
n = len(score)
unique = sorted(set(score), reverse=True)
rank = {s:i for i, s in enumerate(unique)}
for s in score :
if rank[s] == 0 :
print("GOLD")
elif rank[s] == 1 :
print("SILVER")
elif rank[s] == 2 :
print("BRONZE")
else :
print("NONE")入力処理
標準入力から、データの読み込みを行います(ここは、ルール1と同じです)。
score = list(map(int, input().split()))
n = len(score)n=len(score)で、参加者の人数を計算していますinput().split()で、スペース区切りされたスコア(20 30 40 ...)を読み込んでリスト['20', '30', '40', ...]します。※この時点では文字列ですmap(int, ...)で、文字列リストの要素全てを整数に変換しますlist(...)で、それを整数リストとしてscoreに格納します
順位づけテーブル作成
unique = sorted(set(score), reverse=True)
rank = {s:i for i, s in enumerate(unique)}どのスコアが何位になるかを高速で調べるための対応表「辞書(dict)」を作成します。
set(score)scoreリストから重複をなくし、ユニークな(固有の)スコアだけの集合を作ります(例:{20, 30, 90, 100})。Pythonの場合は、setに変換することで重複を削除できます。sorted(..., reverse=True):
作成した重複なしのスコアをreverse=True(降順、つまり点数が高い順)に並べ替えたリストuniqueを作ります(例:[100, 90, 30, 20])rank = {s:i ...}uniqueリストを元に、スコアをキー、順位(インデックス)をバリューとする辞書rankを作成します。enumerate(unique)は、リストの要素を(インデックス, 値)のペアで取り出します。(例:(0, 100),(1, 90),(2, 30), …){s:i ...}は、値s(スコア)をキー、インデックスi(順位)をバリューとする辞書を作ります。- 結果:
rankは{100: 0, 90: 1, 30: 2, 20: 3}となります。
これで「100点は0位 (金)」「90点は1位 (銀)」「30点は2位 (銅)」という対応表が完成しました。
出力処理
for s in score :
if rank[s] == 0 :
print("GOLD")
elif rank[s] == 1 :
print("SILVER")
elif rank[s] == 2 :
print("BRONZE")
else :
print("NONE")各参加者のスコア(score)が辞書rankで何番目かをチェックし、0ならGOLD, 1ならSILVER, 2ならBRONZE, それ以外の場合はNONEを表示します。
以上が、プログラムの内容になります。
ルール1とルール2の違い
ルール1は上位の順位の人の人数、ルール2はスコアの1〜3位でメダルがもらえるという違いでしたが、プログラムはかなり違うことがわかります。とりあえず、順位を出力するプログラムの場合は、この2パターンを押さえておけば、大抵の場合に対応できるのではと思います。
まとめ
この記事では、順位に対してメダルを付与する処理を、Pythonで記述する方法について、代表的な2つのルールについてサンプルプログラムを提示して解説しました。競技プログラミングなどだけではなく、結構使う場合がありますので、作り方を覚えておくと良いです。

