LoginSignup
2
1

More than 1 year has passed since last update.

【競プロ典型90問】002の解説(python)

Last updated at Posted at 2021-08-05

概要

競プロ典型90問の解説記事です。
解説の画像を見ても分からない(理解力が足りない)ことが多々あったので、後で解き直した際に確認できるようまとめました。

※順次、全ての問題の解説記事を挙げていく予定です。
※★5以上の問題は難易度的に後回しにしているため、投稿時期が遅くなる可能性があります。(代わりに丁寧に解説してくれる方いたらぜひお願いします

問題002-Encyclopedia of Parentheses

問題概要

長さNの「正しい」カッコ列を辞書順で出力する。
正しいとは、
- ()のペアが揃っている。
- 右から見て行った時に、"("より")"の方が多くなってはいけない
- ()以外の文字列が含まれてはいけない

制約


1 <= N <= 20 \\
Nは整数

解き方

Nが小さく、文字列のシンプルさから、工夫して全探索で求められそう。
一応、同じものを含んだ並び替えで全パターン列挙することも考えたが、パターンが最大で $20!$ となってしまうため、
しんどそう。(厳密には、$20!/(10!*10!)$)

そこで今回は、
1. "(" を1, ")" を0とみなして、ビット全探索
2. 1で出てきた文字列において "(" より先に ")" が多く出現しないか確認
といった流れで実装していく。

1に関して、0か1かの2通り × N文字 なので、$O(2^N)$の計算量。
(ビット全探索に関してはこちら

2に関して、N文字を左から検索するだけなので、$O(N)$。

2^Nのパターンにおいて、N回の検索を行うので、
合計で$O(N*2^N)$。これは、10^7のオーダーになるので、十分に間に合う。

参考画像

引用元:競プロ典型90問 Github

実装

answer.py

# 入力の受け取り
N = int(input())

# カッコ列を格納する配列
pare = []

# ビット全探索
for i in range(1 << N):

# 1の時 "(" を、0の時 ")" を文字列に追加していく
  l = ""
  for j in range(N):
    if i >> j & 1:
      l += "("
    else:
      l += ")"

# 文字列の長さがNの時のみ、左から検索する。その時cntで"("と")"の出現回数を計算する。cntが0より小さくならなかった+cntが0(出現回数が等しかった)文字列のみをpareに格納する
  if len(l) == N:
    cnt = 0
    flag = True
    for k in range(N):
      if l[k] == "(":
        cnt += 1
      else:
        cnt -= 1
      if cnt < 0:
        flag = False
    if flag and cnt == 0:
      pare.append(l)

# pareを辞書順にソート、順番に出力する
pare.sort()

for i in range(len(pare)):
  print(pare[i])

※ちなみに、上記のコードは、Pythonで提出するとTLEになり、pypyだとACになります。
やたらと長い配列や再起関数を用いる場合を除いては、pypyの方が基本的に早いので、提出はpypyがおすすめです。
参考記事

最後に

問題の解説を読んでも他の人のコードを見てもさっぱり分からないという方の
力に少しでもなれれば幸いです。
コードの改善点やその他、ご意見などあれば、気軽にコメントください。

ここまでお読みいただきありがとうございました。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1