AtCoder向けpythonチートシート(入力編)|Pythonで競技プログラミグ
PythonでAtCoderを始める方に向けに、頻出する入力処理のパターンを網羅しました。この記事で、AtCoderの問題の入力処理の書き方が大体理解できると思います
入力以外のチートシートは以下のリンクにあります
その他のAtCoderに役立つ記事の一覧は以下にあります。
はじめに
ディープラーニングやデータ分析、機械学習を目的としてPythonを学習しようとしている方は多いと思います。データ分析はPandasやnumpyの使い方を、ディープラーニングではPytorchやtensorflowなどのフレームワークの使い方を学習することになりますが、これらの学習は基本的なPythonの使い方を知っていることが前提となります。
プログラミングの基礎を学習する練習問題として、AtCoderの問題を解くのは役に立ちます。私自身、PythonとGo言語でのコーディングの練習を兼ねて、AtCoderの問題を解いています。
Pythonで問題を解く時に最初に躓くのが、「入力」の部分です。
というのも、普段、あまり標準入力からデータを受け取ることがないため(ファイルなどから読み込むことが多い)、標準入力からデータを入力するコードを書くことが少ないからです。
この記事では、AtCoderを始めた人のために、Pythonで入力を受け取るパターンを網羅しました。この記事に書いてあるパターンで、基本的な入力パターンがわかると思います。
この記事の内容
この記事では、競技プログラミングを始めた人に向けて、特に入力処理について解説しています。
AtCoderでは、入力は「標準入力」から与えられます。
入力のパターンはある程度決まっています。ここでは、それぞれの入力パターンに対する書き方を説明しています。入力の受け取り方で悩むのは勿体無いので活用してください。
データ入力チートシート
整数Nだけを受け取る(整数1つを受け取る)
input()
で入力後、int
で整数型に変換します
$N$
N = int(input())
整数N, Mを受け取る(複数の整数を受け取る)
一行に複数の入力がある場合は、input().split()
で要素毎に分割できます。
また、map(int, input().split())
で、分割した要素を整数型に一気に変換できます。
$N \ M$
N, M = map(int, input().split())
N個の配列Aを受け取る
配列を受け取る場合には、整数のlist(map(int, input().split())
とします。list
は、map
で変換した結果を配列に変換する記述です。
$N$
$A_1\ A_2\ A_3\ … \ A_N$
N = int(input())
A = list(map(int, input().split()))
1行全体をリストに入れるので、Nは特に指定する必要ありません。
N個の文字列を読み込む
N個の文字列を読み込むには、[input() for _ in range(N)]
と書けば一行で書くことができます。[]
はリストを作成する宣言で、Pythonでは、中にfor
文を書くことができます。
$N$
$string_1$
$string_2$
$string_3$
$:$
$string_N$
N = int(input())
s = [input() for _ in range(N)]
for文の応用です。
配列を0…N-1で初期化したい場合は、以下のように書くことができます。
x = [i for i in range(N)]
H行W列の’#’,’.’のグリッド情報を読み込む
AtCoderでは、迷路などの入力でよくあるパターンです。
$H \ W$
$S_{11} … S_{1W}$
$:$
$S_{H1} … S_{HW}$
具体的には、以下のようなデータです。
3 4
....
#...
.#..
これも、for
を使って以下のように書くことができます。
H, W = map(int, input().split())
S = [input() for _ in range(H)]
読み込んだ配列Sの要素にはS[i][j]
としてアクセスできます
M個の$u_i,v_i$を読み込む
グラフ問題の入力によくあるパターンです。
点がN個、辺がM本、$u,v$が辺で双方向に接続されているという場合の、グラフデータの読み込みです。
$N \ M$
$u_1\ v_1$
$:$
$u_M\ v_M$
以下のように記述することでnode[i][j]=i番目の点が接続している辺の集合になります。
N, M = map(int, input().split())
node = [[] for _ in range(N)]
for _ in range(M):
u, v = map(int, input().split())
u-=1
v-=1
node[u].append(v)
node[v].append(u)
上記は双方向に接続される場合です。
u→vのみ接続する場合は、以下のようにします(node[u].append(v)
でu→vだけ追加)
N, M = map(int, input().split())
node = [[] for _ in range(N)]
for _ in range(M):
u, v = map(int, input().split())
u-=1
v-=1
node[u].append(v)
例えば、node[0]に点0と接続している点のリストが保存されます
H行W列の$A_i,j$を読み込む
H行W列のデータを読み込むパターンです
$H \ W$
$A_{11} … A_{1W}$
$:$
$A_{H1} … A_{HW}$
具体的には、以下のようなデータになります
3 4
1 2 3 4
5 6 7 8
9 10 11 12
少し複雑ですが、これまで説明してきたものの応用です。
list(map(int, input().split()))
で行を分割しながら入力を読み込み、それをfor _ in range(H)
でH回繰り返しています
H, W = map(int, input().split())
A = [list(map(int, input().split())) for _ in range(H)]
配列A, Bを読み込んで、[$A_i, B_i$]の配列に変換
配列A, Bを読み込んで、[Ai, Bi]のペアの形の配列にするパターンです。Aで[Ai, Bi]の組みをソートしたい場合などに使います。
$N$
$A_1\ A_2\ A_3\ … A_N$
$B_1\ B_2\ B_3\ … B_N$
p
に[ai, bi]のリストが保存されます。
N = int(input())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
p = [[x, y] for x, y in zip(a, b)]
先に書いたように、(a, b)の組みをソートする時に使います。bでソートしたい場合は、(b, a)の形でpを作っておくと楽です。
個数が指定されてない整数を受け取る
AtCoder Beginner Contest 344 B問題で初めて見かけたパターンです。
$A_1$
$A_2$
$ \ : $
$A_N$
読み込めないとエラーが発生するのを利用した方法です(try-exceptを使う)
a = []
while True :
try :
a.append(int(input()))
except EOFError:
break
ABC344B問題は、末端が“0”だったので0が来たら終了とすればよかったですが、0でない場合でもOKは方法を追加しました。
おわりに
とりあえず、上にあげたパターンを覚えていれば、大抵の入力で困ることはないと思います。
ちなみに、Pythonは[i for i in range(N)]
みたいな記述ができて便利ですが、これに慣れすぎるとと他のプログラミング言語で苦労するかもしれません。
入力に関しては、気になったものを不定期で追加していきたいと思います。また、解法についても記事にしていく予定です。