ryo’s blog

日々学んだことをまとめています.

競プロ典型90問 002(★3) next_permutation

002 - Encyclopedia of Parentheses(★3)

問題

長さNの正しいカッコ列を出力する。

条件

  • () は正しい。
  • Sが正しいとき、 ( + S + ) は正しい。
  • S,Tが正しいとき、文字列 S + T は正しい。
  • ( の方が ) よりも辞書順で早いものとする。

解法

まず奇数の場合は何も出力しない。

Nの半分ずつを () で埋めた文字列を作る。

左から順に見ていって ( の数より ) の数が多くなったら条件を満たさない。

後は逐一 () の確認をしながら next_permutation で辞書順に出力していく。

(())()   # OK
())(()  # NG

所感

辞書順に出力するという条件から next_permutation を使用したが、bit全探索でも求められるみたい。

むしろそっちが本筋だったと思うので、気が向いたときに解き直してみたい。

コード

#include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
struct fast_ios { fast_ios(){ cin.tie(nullptr), ios::sync_with_stdio(false), cout << fixed << setprecision(20); }; } fast_ios_;
const int INF = (int)1e9;
const ll INFL = (ll)1e18;
const int MOD = 1e9 + 7;
const double EPS = 1e-10;
int dx[]={0, 0, -1, 1};
int dy[]={1, -1, 0, 0};
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }

int main()
{
    int n;
    cin >> n;

    if (n % 2 == 1) return 0;
    string s;
    rep(i,n / 2) s.push_back('(');
    rep(i,n / 2) s.push_back(')');

    do
    {
        int cnt = 0;
        rep(i,n)
        {
            if (s[i] == '(') cnt++;
            if (s[i] == ')') cnt--;
            if (cnt == -1) break;
        }
        if (cnt == -1) continue;
        cout << s << endl;
    } while (next_permutation(s.begin(), s.end()));
    return 0;
}