#include <iostream>
#include <vector>
using namespace std;
using vi = vector<int>;
using vvi = vector<vi>;
vvi conn;
int cnt_pair(vi& check, int i) {
while (i < check.size() && check[i]) ++i;
if (i == check.size()) return 1;
int ret = 0;
check[i] = 1;
for (int j = i + 1; j < check.size(); ++j) {
if (check[j] || !conn[i][j]) continue;
check[j] = 1;
ret += cnt_pair(check, i + 1);
check[j] = 0;
}
check[i] = 0;
return ret;
}
int main() {
int tc;
cin >> tc;
while (tc--) {
int n, m;
cin >> n >> m;
conn = vvi(n, vi(n, 0));
for (int i = 0; i < m; ++i) {
int a, b;
cin >> a >> b;
conn[a][b] = conn[b][a] = 1;
}
vi check(n, 0);
cout << cnt_pair(check, 0) << endl;
}
return 0;
}
학생들을 매칭할 수 있는 경우의 수
- 이고 매칭되지 않은 학생 중 최소인 를 탐색하고 이를 에 대입
- 와 매칭할 수 있는 친구 를 탐색, 짝을 맺을 수 있다면 를 기록
- 방금 짝이 맺어진 와 를 제외한 나머지 학생들의 매칭 가능한 수 를 현재 함수의 결과값에 누적
- 이를 와 짝을 맺을 수 있는 모든 에 대하여 반복
실수한 부분은 와 연결 가능한 의 조건 작성이었다.
if (check[j] || !conn[i][j]) continue;
의 짝이 될 수 있으려면 다른 친구와 짝을 맺지 않고 와 친구 사이여야 한다. 첫 번째 구현에서 이를 정확히 고려하지 못해 아래와 같이 구현했다.
if (!conn[i][j]) continue; // 🚨WRONG
이는 의도와 달리 이미 짝을 맺었더라도 와 친구 사이라면 중복해서 짝을 맺을 수 있다 평가한다.