AtCoder Beginner Contest 213をPythonで解く

投稿日:  更新日:2022/09/02

Atcoder Python

B!
Daniel AgreloによるPixabay(https://pixabay.com/)からの画像

こんにちは, Shinoryoです.

今回はAtCoder Beginner Contest 213を, Pythonで解いてみた結果を書き連ねていこうと思います.

A - Bitwise Exclusive Or

答えは0から255までの整数であることが分かっているので, それを全探索すればよいです. Pythonにおいて, XOR^で求められます.

# 入力
A, B = [int(x) for x in input().split()]
# Cを0から255まで試す
for C in range(256):
if A^C == B:
break
# 出力
print(C)

あるいは, AXORC=Bの両辺にAXORすることで,

(1)AXORAXORC=AXORB,(2)0XORC=AXORB,(3)C=AXORB,

となります(任意の非負整数Aに対してAXORA, また0XORA=Aとなることを利用). ゆえに, AXORBを求めてもよいです.

# 入力
A, B = [int(x) for x in input().split()]
# 出力
print(A^B)

B - Booby Prize

Aiをソートして後ろから2番目の数字の元のインデックスが答えです. インデックスを保存しておくために, [Ai,i]のリストを作成した上で保存し, ソートします.

# 入力
N = int(input())
A = []
temp = 1
for x in input().split():
A.append([int(x), temp])
temp += 1
# Aにはインデックス情報も明示的に入れている(各項2番目)
# 1番目に合わせてソート
A_sorted = sorted(A)
# 出力
print(A_sorted[-2][1])

C - Reorder Cards

行に関する操作と列に関する操作は互いに独立なので, 行と列に関しては別に考えることができます.

数の書かれたカードを含まない行を消去するという操作を繰り返すことによって,

  • もともと最も上にあった数の書かれたカード→操作後の1行目に移動
  • もともと上から2番目にあった数の書かれたカード→操作後の2行目に移動
  • ……

のようにカードが移動されます. ゆえに, リストAiの各要素を, それらの大小関係(イコールも含む)を維持したまま値を小さくすることが求められます.

以上の話は, 列に関しても同様に考えることができます.

これはいわゆる座標圧縮(coordinate compression)と呼ばれる操作になります. 以下ではソートを利用し, 「元の値」と「その順位」の関連付けの辞書(dict型)を作成することで記述しています.

辞書型はX_dict = {key: value}のように作成します. 特定のkeyに対するvalueを得たい場合には, X_dict[key]のようにします.

# 入力
H, W, N = [int(x) for x in input().split()]
A = []
B = []
for i in range(N):
A_temp, B_temp = [int(x) for x in input().split()]
A.append(A_temp)
B.append(B_temp)
# Aのセット(setで重複を消す)の要素をRankに変える
A_sorted = sorted(list(set(A)))
A_dict = {A_sorted[i]:i for i in range(len(A_sorted))}
# Bのセット(setで重複を消す)の要素をRankに変える
B_sorted = sorted(list(set(B)))
B_dict = {B_sorted[i]:i for i in range(len(B_sorted))}
# 出力 Indexに注意
for i in range(N):
print(A_dict[A[i]] + 1, B_dict[B[i]] + 1)

上のコードでは, 要素のランク(順番)を得るためにインデックス番号を取得することが重要となります. 上のコードではfor文などで取得していますが, Pythonにはenumerate()関数があり, リストやタプルなどの要素と同時にインデックス番号を取得することができます. 「インデックス番号, 要素」の順に得られることに注意してください.

# 入力
H, W, N = [int(x) for x in input().split()]
A = []
B = []
for i in range(N):
A_temp, B_temp = [int(x) for x in input().split()]
A.append(A_temp)
B.append(B_temp)
# Aのセット(setで重複を消す)の要素をRankに変える
A_dict = {i:j for j, i in enumerate(sorted(list(set(A))))}
# Bのセット(setで重複を消す)の要素をRankに変える
B_dict = {i:j for j, i in enumerate(sorted(list(set(B))))}
# 出力 Indexに注意
for i in range(N):
print(A_dict[A[i]] + 1, B_dict[B[i]] + 1)

D - Takahashi Tour

この問題では, 都市を頂点, 道路を辺としたグラフを考えることができます. 例えば, 「入力例 1」の場合であれば, 下図のようになります.

今回の高橋くんのような移動の仕方は, 深さ優先探索(depth-first search, DFS)と呼ばれるものに対応します. 行き止まりの(最も末端の)ノードに行きつくまで, 経路を戻らずに隣接ノードを進んでいく探索方式のことを指します. 下図は, 深さ優先探索におけるグラフの探索順を示しています.

Depth-first-tree
Wolfram Esser, CC BY-SA 3.0, via Wikimedia Commons.

この高橋くんの旅は, 以下の動作を繰り返すことで実現できます. 「now_city」は, 訪れた都市を順に格納していくリストです. 「visited」は, その都市を訪れたことがあるかどうかを表すフラグを格納したリストです.

  1. now_cityに, 都市Aを格納する.
  2. visitedに, 都市Aを訪れたことを記録する.
  3. 都市Aから訪れることができる都市を調べる(都市A-a, 都市A-b, ……)
  4. 都市A-a, 都市A-b, ……の全てにおいて, 上記(1,2,3,4)を繰り返す.
  5. 再度, 都市Aを訪れる.

このような動作は, 再帰関数を用いることで実現できます.

一部のテストケースにおいて, 「maximum recursion depth exceeded while calling a Python object」というエラーが出てくることがあります. これは再帰回数の上限に引っかかっていることによるものです. 以下のように, 再帰回数の上限を引き上げることで解決できます.

import sys
sys.setrecursionlimit(10**6) 
import sys
sys.setrecursionlimit(10**6)
# 入力
N = int(input())
# 各都市から行ける都市のリストを作成
# 0番目は放棄
can_go_city = [[] for _ in range(N + 1)]
for _ in range(N - 1):
A_temp, B_temp = [int(x) for x in input().split()]
can_go_city[A_temp].append(B_temp)
can_go_city[B_temp].append(A_temp)
# can_go_cityのソート
for can_go_city_ele in can_go_city:
can_go_city_ele.sort()
# 訪れた都市のリストを作成
now_city = []
visited = [False]*(N+1)
# 今は都市1にいる
visited[1] = True
# 都市candidate_cityから新たに訪れることができる都市を探し、
# その都市番号をnow_cityに加える関数
def survey(candidate_city):
now_city.append(candidate_city)
visited[candidate_city] = True
for candidate_next_city in can_go_city[candidate_city]:
if not(visited[candidate_next_city]):
survey(candidate_next_city) # 再帰関数
now_city.append(candidate_city) # 元の都市に戻る
# 都市1からsurvey()を実行
survey(1)
# 出力
print(" ".join([str(ele) for ele in now_city]))

E以降

E以降は私の能力不足故に省略いたします.

参考にしたサイト等