Python
Python3
競技プログラミング

Pythonで競プロをやる時にそこそこ使う書き方(itertools編)

誰向け?

競プロをしていて組み合わせを全パターン列挙したいことはありませんか?
私はあります。

そんな時どうしますか?
for文使いますか?
ネストが深くなります。

そもそも書き方がわかりませんか?
確かに...ワカル...

そんな時にPython標準ライブラリのitertoolsが役に立ちます。
自分でも最近使ってみて便利だと思ったので記事にまとめることにしました。

AtCoder最近始めました。Pythonistaです。
みたいな人のお役に立てればなぁと思います。

何が出来るの

itertoolsを使えば順列、組み合わせ、重複順列、重複組合せのパターンを全列挙できます。

import itertools

順列

n個の要素からr個選んで一列に並べる時のパターン$nPr$の列挙
rを省略した場合は$nPn$となります。
iterableには配列以外に文字列とかも入れることが出来ます。

permutations.py
itertools.permutations(iterable, r)

list(itertools.permutations([1, 2, 3, 4], 2))
# -> [(1, 2), (1, 3), (1, 4), (2, 1), (2, 3), (2, 4), 
#     (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 3)]

list(itertools.permutations([1, 2, 3]))
# -> [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

list(itertools.permutations(range(3), 2))
# -> [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]

組み合わせ

n個の要素からr個選ぶ組み合わせ$nCr$の列挙
permutationsと違って第2引数が必須です。

combinations.py
itertools.combinations(iterable, r)

list(itertools.combinations([1, 2, 3, 4], 2))
# -> [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

list(itertools.combinations(range(3), 2))
# -> [(0, 1), (0, 2), (1, 2)]

重複順列

n個の要素から重複を許していち列にr個並べる時のパターン$n^r$の列挙
こちらも第2引数は必須かつrepeat=は省略できません。

product.py
itertools.product(iterable, repeat=1)

list(itertools.product(range(3), repeat=2))
# -> [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

list(itertools.product([-1, 1], repeat=3))
# -> [(-1, -1, -1), (-1, -1, 1), (-1, 1, -1), (-1, 1, 1), 
#     (1, -1, -1), (1, -1, 1), (1, 1, -1), (1, 1, 1)]

重複組合せ

n個の要素から重複を許してr個選ぶ組み合わせ$nHr$の列挙
正直使ったこと無いけど一応

combinations_with_replacement
list(itertools.combinations_with_replacement(range(3), 2))
# -> [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)]

それぞれ、返り値がイテレータになっているので上の例ではlist()をつけましたが、
for文内で使う時はlistはいりません。

for a, b, c in itertools.product([-1, 1], repeat=3):

最後に

実装が重い問題とかだと特に、こういったアルゴリズムの本質じゃない所の手間をなるべく減らしたくなりませんか?itertoolsのおかげでそこの所は大分改善されたかなぁと思います。他にもnumpyやcollections, mathとかをAtCoderでは使うので、機会があればまたまとめるかもしれません。最後に、実際に自分がitertoolsを使って解いた問題を置いておきます。

最近itertoolsを使った問題

ABC028 C - 数を3つ選ぶマン
ABC029 C - Brute-force Attack
ABC073 D - joisino's travel
ABC100 D - Patisserie ABC