Official
C - Graph Isomorphism Editorial by KoD
整数 \(X_{i, j}\) を、高橋君のおもちゃにおいてボール \(i, j\) を結ぶひもが存在するなら \(1\)、そうでないなら \(0\) と定めます。
同様に、整数 \(Y_{i, j}\) を、青木君のおもちゃにおいてボール \(i, j\) を結ぶひもが存在するなら \(1\)、そうでないなら \(0\) と定めます。
\((1, 2, \dots, N)\) を並べ替えて得られる順列 \(P\) を全探索することを考えます。\(P\) が条件をみたすことは、次が成り立つことと同値です。
- 任意の \(1 \leq i \leq N, 1 \leq j \leq N\) に対し \(X_{i, j} = Y_{P_i, P_j}\)
これが成り立つかどうかは \(O(N^2)\) で判定することができます。\(P\) としては \(N!\) 通りあるので、全体の計算量は \(O(N^2 \times N!)\) となり、実行時間制限に間に合います。
順列の全列挙は、C++ であれば std::next_permutations
、Python であれば itertools.permutations
を使うのがよいでしょう。
実装例 (C++) :
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector x(n, vector<bool>(n)), y(n, vector<bool>(n));
for (int i = 0; i < m; ++i) {
int a, b;
cin >> a >> b;
a -= 1, b -= 1;
x[a][b] = x[b][a] = true;
}
for (int i = 0; i < m; ++i) {
int c, d;
cin >> c >> d;
c -= 1, d -= 1;
y[c][d] = y[d][c] = true;
}
vector<int> p(n);
iota(begin(p), end(p), 0);
int ans = 0;
do {
bool ok = true;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (x[i][j] != y[p[i]][p[j]]) {
ok = false;
}
}
}
if (ok) {
cout << "Yes\n";
return 0;
}
} while (next_permutation(begin(p), end(p)));
cout << "No\n";
}
実装例 (Python) :
import itertools
n, m = map(int, input().split())
a = [[False] * n for _ in range(n)]
b = [[False] * n for _ in range(n)]
for _ in range(m):
u, v = map(int, input().split())
u -= 1
v -= 1
a[u][v] = a[v][u] = True
for _ in range(m):
u, v = map(int, input().split())
u -= 1
v -= 1
b[u][v] = b[v][u] = True
ans = False
for p in itertools.permutations(range(n)):
ok = True
for i in range(n):
for j in range(n):
if a[i][j] != b[p[i]][p[j]]:
ok = False
if ok:
ans = True
print("Yes" if ans else "No")
posted:
last update: