[종만북] 230912 (화)

Jiseok Son·2023년 9월 12일
0

6.3 문제: 소풍(PICNIC)

#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;
}

cnt_pair(check,i):=i to ncnt\_pair(check, i) := i \text{ to } n 학생들을 매칭할 수 있는 경우의 수

  • ixi \le x이고 매칭되지 않은 학생 중 최소인 xx를 탐색하고 이를 ii에 대입
  • ii와 매칭할 수 있는 친구 jj를 탐색, 짝을 맺을 수 있다면 check[i],check[j]check[i], check[j]를 기록
  • 방금 짝이 맺어진 iijj를 제외한 나머지 학생들의 매칭 가능한 수 cnt_pair(check,i+1)cnt\_pair(check, i + 1)를 현재 함수의 결과값에 누적
  • 이를 ii와 짝을 맺을 수 있는 모든 jj에 대하여 반복

실수한 부분은 ii와 연결 가능한 jj의 조건 작성이었다.

if (check[j] || !conn[i][j]) continue;

ii의 짝이 될 수 있으려면 다른 친구와 짝을 맺지 않고 ii와 친구 사이여야 한다. 첫 번째 구현에서 이를 정확히 고려하지 못해 아래와 같이 구현했다.

if (!conn[i][j]) continue; // 🚨WRONG

이는 의도와 달리 이미 짝을 맺었더라도 ii와 친구 사이라면 중복해서 짝을 맺을 수 있다 평가한다.

profile
make it work make it right make it fast

0개의 댓글