bit全探索 atcoder abc054 c

ABC054 C - One-stroke Path

ABC054 C - One-stroke Path
Feb. 2, 2020, 1:52 p.m.

目次

問題

https://atcoder.jp/contests/abc054/tasks/abc054_c

入力

N M
a_0 b_0
a_1 b_1
...
a_M b_M
  • N - 頂点数($2 \leq N \leq 8$)
  • M - 辺数($0 \leq M \leq N(N-1)/2$)
  • a_i, b_i 無向辺の頂点

出力

頂点1からすべての頂点をちょうど1回ずつ訪問する組み合わせはいくつあるかを答える問題です.

解説

先頭の1だけ固定してそれ以外の頂点を適当に並べます.
そして先頭から末尾まで頂点を辿っていって頂点間をつなぐ辺がすべて存在する場合はカウントします.
1箇所でも途切れている辺があればそれはカウントしません.
これをすべての頂点の並べ方の数だけ試してみれば答えが求まります.
頂点数は$N$なので、先頭の1は固定でその並べ方は$(N-1)!$通りです.
C++ではnext_permutation関数ですべての並べ方を順番に生成することが出来ます.

Nが十分小さいのでこれで間に合います.

計算量

頂点間に辺が存在するかの確認は頂点を先頭から1つずつ見ていくので計算量$O(N-1)$です.
それを$(N-1)!$通りだけ繰り返します.

$$
O((N-1)! \cdot (N-1))
$$

解答

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#define MAX_N 8
#define MAX_M (8*7*0.5)

Int N, M;
vector<vector<Int> > G(MAX_N, vector<Int>(MAX_N, 0));

void input() {
  cin >> N >> M;
  Int u, v;
  loop(m,0,M) {
    cin >> u >> v;
    u--,v--;
    G.at(u).at(v) = 1;
    G.at(v).at(u) = 1;
  }
}

Int bit() {
  vector<Int> path;
  loop(n,0,N) path.push_back(n);
  Int numPaths = 0;
  do {
    bool ok = true;
    loop(i,1,path.size()) {
      if (!G.at(path.at(i-1)).at(path.at(i))) {
        ok = false;
        break;
      }
    }
    if (ok) numPaths++;
  } while (next_permutation(path.begin()+1, path.end()));
  return numPaths;
}

void solve() {
  cout << bit() << endl;
}

int main(void) {
  input();
  solve();
  return 0;
}