プログラムを勉強するモチベーションを保つ、逆に勉強したことを実践で活用させる場を求める、など様々な理由で競技プログラミングやオンラインジャッジをされる方がいると思います。
今では数多くのサイトがあるので、自分のペースや実力に合わせて楽しむことが容易になっています。
もし気になる方には、参考として以下の記事へリンクを張っておきます。
今回も備忘録を兼ねると同時に、オンラインジャッジに参加するハードルを(I/O関係で)下げるお手伝いをしたいと思います。
#1 でもPython3.x使うの?
と言われそうなので先に断りを。
基本的にオンラインジャッジは自分が習得しているプログラミング言語で、対応しているものを使えばいいと思います。
大概はC(++)とか使う方が多いでしょうし、計算速度を求めるならその方がいいでしょう。
一方、プログラム経験者の中にはPythonを用いる方も一定数いるでしょうし、最近では人工知能含めたライブラリが豊富であることも考えるとPython経由でプログラミングの世界に足を踏み入れた方もいると思います。
そんな方々が「オンラインジャッジでいろいろ勉強しよう」と思い立った時に、最初は入出力で苦労すると思います。
僕は今でも苦労しています。
当然ながら以下のような記事を書いてくださっている先駆者もいます。
僕もお世話になっていますが、どうも文法が2.x系と古いように思われます。
てことで、3.x用の記事を書いておくことにしました。参加者の方々の参考になればと。
#2 入力
##1: 1行で何か一つ
X
var = input()
これで変数var
にX
が代入されます。この場合変数には文字列扱いで代入がなされるので、必要ならばint(input())
やfloat(input())
などの操作が必要になります。
##2: 複数行の入力
オンラインジャッジ系では、まず1行目にデータ数、2行目以降にインプットデータ、といった形式が取られる場合があります。
その場合、Pythonではリスト形式でインプットを行うと扱いが楽になるでしょう。
5 # データの数 N
1
2
3
4
5
n = int(input())
a = [input() for i in range(n)]
これで、a
にはリスト形式で値が代入されます。ただしここでも文字列形式です。出力のところで後述しますが、リストでの変数の型は整数なのか浮動小数点なのかあるいは文字列のままか、必要に応じて考えた方がいいでしょう。
なお、上で紹介した記事ではインプットがraw_input()
になっていますが、これは2.x時代のもので、3.xではinput()
に統合されたそうです。今後はinput()
を用いましょう。
##3: 1行で複数の値を代入する
これもオンラインジャッジの入力形式ではよくあります。この手のパターンは2通りあると思っているのでそれぞれ見ていきましょう。
複数の変数に代入する場合
例えば、a b ...
みたいな形式で複数変数に代入したい場合、map
を使います。例えば3つの整数を格納したい場合。
#Example array
1 2 3
a, b, c = map(int, input().split())
これでa=1, b=2, c=3
と問題なく代入されます。これに関して、
Pythonで競技プログラミングする時に知っておきたいtips(入出力編) 中で
リストの要素数が左辺の数に一致していれば,左辺それぞれの変数にリストの各要素を代入できる.
こういう形式の代入を「アンパック代入」というらしい.競技プログラミングの場合,入力の要素数が明らかで,かつ少ない場合のみ使うとよい.
と書かれています。そのようにして大いに活用しましょう。
配列のように一連のデータで扱いたい場合
Pythonで配列のごとく扱うためには、もちろんリストを使います。ただ、3.xは2.x時代と違いすぐ上で行ったような文法が素直に通用しません。
少しだけこの様子を見ることにしましょう。
a = map(int, input().split())
2.x時代はinput()
のところをraw_input()
と読み替えることで通用していたようです。しかしながら、3.xからはmap
はオブジェクトとして扱われるようになったために、リストと同じ感覚でそのまま扱おうとするとエラーになります。
例えばa = ["2", "1", "3"]
みたいになっていたとして、ソートしたいと次のようなif
文を考えましょう。
if int(a[i]) < int(a[j]):
# 何がしかの処理
ただし、i, j
はカウンタ変数だと思ってください。ソートの例なので・・・。
すると、たぶんこのようにエラーが返ってきます。
TypeError: 'map' object is not subscriptable
これは誤解を恐れず言うならば、map
とlist
は型が異なっている、ということです。
この問題を解決するためには、map
をlist
に型変換してしまうことです。すなわち、以下のようにします。
a = list(map(int, input().split()))
これで解決しました。
#3 出力
##1: 改行ありの1変数
普通にprint
を使えば大丈夫です。なお2.xから3.x系に変わった段階で何度も言われていますが、カッコを忘れないようにしましょう。
print(a) # 変数 a の値を出力
##2: 行末改行ありの複数変数
これはprint
で複数の変数を並べるだけです。
print(a,b,c)
自動的に半角スペース1文字区切りで出力されます。
##3: リストを整数化して並べて出力したい
おそらくこれがハイライトになるでしょう。慣れないとおそらく苦労します。
これはjoin
を用いるのが分かりやすいです。
以下の例では0~4の数字を半角スペース区切りで出力します。
a = [str(i) for i in range(5)] # あえてここでは"文字列"として0~4をリスト化
print(" ".join(a)) # 半角スペース区切り
# -> 0 1 2 3 4
ただし、この段階で先に書いたように注意が必要になります。
join
は引数が文字列の型にしか利用できないことです。これが整数int
だとどうなるか?
a = [int(i) for i in range(5)] # 本来は不要だが明記する意味でintを追加して0~4をリスト化
print(" ".join(a)) # 半角スペース区切りで出力したい
# -> TypeError: sequence item 0: expected str instance, int found
となり、エラーとなります。
また型が"文字列"のまま出力してしまった場合、判別機によってはRuntime Errorを返す場合があります。
これはコンソールでデバッグする際に盲点となります。アルゴリズムや出力形式も正しそうに見えるのにうまくいかない場合は、この点も注意するといいでしょう。
(2017/05/28 追記)
@shiracamus さんのコメントより
str でも int でも何でも、半角スペース区切りで出力したいなら次のように書けます。
a = [1, 'abc', 2.34, 5+6j] print(*a) #-> 1 abc 2.34 (5+6j)
本文中のように型を考える必要がない分だけ、スマートだと思います。
参考になりました、ありがとうございます。
##4: フォーマットを指定したい
Python3.xからはCライクな%表記よりもformat
形式が推奨されています。
Python系ではあまり気にしなかったかもしれませんが、計算誤差を一定以下の場合許容するようなジャッジや、出力が指定されている場合に威力を発揮するでしょう。というか、そうしないと受け入れられないでしょう。
a = 10
b = 1.234567
print("Example: a={:05d}, b={:.3f}".format(a,b))
#-> Example: a=00010, b=1.235
{}内のコロン:を忘れると怒られます。気を付けましょう。
format
の詳細については検索するなりリファレンス読むなりしてください。
おわりに
ざっと書いてきましたが、おそらくこれだけ知っておくと組み合わせ方で応用が利くと思います。
何か足りなければコメントください。
それでは良いプログラミングライフを!