値の整列
値の整列
nums = [int(input()) for _ in range(4)]
print(*sorted(nums), sep='\n')
シープラスプラスプラス
シープラスプラスプラス
n = int(input())
print('C' + '+' * n)
文字列もかけ算が先です。😄
大晦日
大晦日
y, m, d = input().split('-')
if m == '12' and d == '31':
print('Yes')
else:
print('No')
背の順に並んでいるか
背の順に並んでいるか
n = int(input())
a = [int(input()) for _ in range(n)]
if a == sorted(a):
print('Yes')
else:
print('No')
入力をリストで受け取り、そのリストが昇順ソートしたリストと同じなら背の順に並んでいると言えます。
遠足のお菓子
遠足のお菓子
N, X = map(int, input().split())
x = sum(int(input()) for _ in range(N))
if x <= X:
print('Yes')
else:
print('No')
入力 x を全部足して X と比較するだけです。
陣取りゲーム
陣取りゲーム
class Game:
def __init__(self, name, h, w):
self.name = name
self.adjacents = {(h, w)}
self.cnt = 1
def bfs(self):
new_locates = set()
while self.adjacents:
y, x = self.adjacents.pop()
for ny, nx in self.NSWE:
yy = y + ny
xx = x + nx
if (0 <= yy < self.H and 0 <= xx < self.W) and self.S[yy][xx] == '.':
new_locates.add((yy, xx))
self.cnt += 1
self.S[yy][xx] = self.name
self.adjacents = new_locates
@classmethod
def initialize(cls, H, W, S, turn, players):
cls.H = H
cls.W = W
cls.S = S
cls.turn = turn
cls.players = players
cls.NSWE = ((-1, 0), (1, 0), (0, -1), (0, 1))
@classmethod
def play(cls):
while any(p.adjacents for p in cls.players):
now_player = cls.players[cls.turn]
if now_player.adjacents:
now_player.bfs()
cls.turn = not cls.turn
@classmethod
def output_result(cls):
cnt_a = cls.players[0].cnt
cnt_b = cls.players[1].cnt
print(cnt_a, cnt_b)
print('A' if cnt_a > cnt_b else 'B')
def setup():
H, W = map(int, input().split())
N = input()
S = [list(input()) for _ in range(H)]
names = {'A': 0, 'B': 1}
turn = names[N]
players = [None, None]
for h in range(H):
for w in range(W):
char = S[h][w]
if char == 'A' or char == 'B':
players[names[char]] = Game(char, h, w)
Game.initialize(H, W, S, turn, players)
return
def main():
Game.play()
Game.output_result()
if __name__ == '__main__':
setup()
main()
AとBの各プレイヤーが持つ情報が多いので、クラス型で作りました。クラス型は解説もラク😊
見るからに幅優先探索(BFS)で作ってくださいと言わんばかりの問題です。
長くて見るのがイヤになるかもしれませんが、重要な所は.bfs() メソッドと、クラスメソッドの .play() メソッドの2つ、稼動部はこの2つだけなんです。
それでは順を追って解説します。
【 入力とインスタンスの作成 】
def setup():
H, W = map(int, input().split())
N = input()
S = [list(input()) for _ in range(H)]
names = {'A': 0, 'B': 1}
turn = names[N]
players = [None, None]
for h in range(H):
for w in range(W):
char = S[h][w]
if char == 'A' or char == 'B':
players[names[char]] = Game(char, h, w)
Game.initialize(H, W, S, turn, players)
return
ここでは入力と、A と B の座標取得を行なっています。A と B が交互に陣取りを進めていきますので、A に 0
、B に 1
を割り当てます。これはここで作られるインスタンスを players
に格納するのですが、この要素番号に使うのと、 .play() メソッド内で A と B のターンを切り換える為の False と True の役目にもなっています。False が 0 でプレイヤーA、True は 1 でプレイヤーBです。
turn
には 入力 N で与えられた先行プレイヤーが格納されているリスト players
の要素番号が代入されます。
の二重ループで A と B の座標を取得します。それぞれの座標を Game クラスの引数に与えてインスタンスを作成します。
Game.initialize() で、クラス内で使用する為の値をまとめて送ります。
【 クラスの準備 】
@classmethod
def initialize(cls, H, W, S, turn, players):
cls.H = H
cls.W = W
cls.S = S
cls.turn = turn
cls.players = players
cls.NSWE = ((-1, 0), (1, 0), (0, -1), (0, 1))
setup() 関数から送られてきたクラス内で使用する値を、各クラス変数に格納します。インスタンスもここに格納してクラス内で使えるようにしておきます。
【 コンストラクタ 】
def __init__(self, name, h, w):
self.name = name
self.adjacents = {(h, w)}
self.cnt = 1
self.name
は、マップ内の占領地に印を付けるために使う文字です。A か B が入ります。
self.adjacents
は、最も外側にある領地の座標が格納されます。この座標を使って周辺に占領できる空白地があるかどうかを調べます。
self.cnt
は、占領したマスの数です。最初は必ず1つから始まりますので 1 を代入します。
準備は以上です。次からいよいよゲームが始まります。
【 .play() メソッド 】
@classmethod
def play(cls):
while any(p.adjacents for p in cls.players):
now_player = cls.players[cls.turn]
if now_player.adjacents:
now_player.bfs()
cls.turn = not cls.turn
main() 関数からこのメソッドが呼び出されます。ここがメインとなるプログラム部分です。ここでは A もしくは B に、次に探索する座標が残っている場合にループします。その後、.bfs() を呼び出し、領地拡大を図ります。
now_player
は、インスタンス cls.players[cls.turn]
に名前を付けて短縮化するために行なっています。値のコピーではなく、アドレス参照です。
ターンを終えたら、次の人とターンを交代します。
- ループは、今回探索する座標が入っている
self.adjacents
が空になるまでです。ここから1つポップして、(y, x) に座標を入れます。 - そして次の ループで
NSWE
(方角) の順に上下左右を探索します。 - チェックする座標がマップの範囲内、もしくは '.' ならば、占領します。'#' という障害物があってもこの条件文の書き方ならお構いなしです。
new_locates
は、この探索中に新しく占領した座標を格納するセットです。self.adjacents
に入れてしまうと、今回探索分と次回探索分が混ざってしまい、マップ全体を探索し尽くしてしまいますので、一時的に別のセットを作ってそこに入れておきます。self.adjacents
は今回探索する座標リスト、new_locates
は次回探索分の座標リストです。- 1つ占領したので、1つカウントします。
- 占領箇所を自分の名前 A または B に書き換えます。フラグを立てるような感じです。
- 今回分の探索を終えると
self.adjacents
は空になり、new_locates
には次回探索分の座標リストが入っています。空になったself.adjacents
にnew_locates
を入れて、次回ターンはこれらの座標を探索します。
【 .bfs() メソッド 】
def bfs(self):
new_locates = set()
while self.adjacents: # 1番
y, x = self.adjacents.pop()
for ny, nx in self.NSWE: # 2番
yy = y + ny
xx = x + nx
# 3番
if (0 <= yy < self.H and 0 <= xx < self.W) and self.S[yy][xx] == '.':
new_locates.add((yy, xx)) # 4番
self.cnt += 1 # 5番
self.S[yy][xx] = self.name # 6番
self.adjacents = new_locates # 7番
while self.adjacents:
y, x = self.adjacents.pop()
for ny, nx in self.NSWE:
yy = y + ny
xx = x + nx
if (0 <= yy < self.H and 0 <= xx < self.W) and self.S[yy][xx] == '.':
new_locates = set()
new_locates.add((yy, xx))
self.cnt += 1
self.S[yy][xx] = self.name
self.adjacents = new_locates
ターンが終了したら .play() メソッドに戻り、次のターンの人に切り換わります。
【 ゲーム終了 】
@classmethod
def play(cls):
while any(p.adjacents for p in cls.players):
if cls.players[cls.turn].adjacents:
cls.players[cls.turn].bfs()
cls.turn = not cls.turn
A と B の adjacents
が共に空になったら全ての探索が終了したことになります。
def main():
Game.play()
Game.output_result()
最後に結果を画面に出力します。
@classmethod
def output_result(cls):
cnt_a = cls.players[0].cnt
cnt_b = cls.players[1].cnt
print(cnt_a, cnt_b)
print('A' if cnt_a > cnt_b else 'B')
引き分けは無いということなので、引き分けの判定無しで簡単に出力しています。