문제 링크: https://www.acmicpc.net/problem/1043
입력 조건이 n, m<=50이기 때문에 여러 방법으로 풀 수 있는데요 제일 간단한 방법인 union-find로 풀어봤습니다.
문제 핵심은 진실을 아는 사람과 같은 파티에 있으면 진실을 아는 것과 동일하게 된다는 것입니다. 파티에 진실을 아는 사람이 있으면 그 파티 참가자 전부 진실을 알게 되는 셈이고, 그 파티 참가자가 다른 파티에 가면 다른 파티 또한 전부 진실을 알게 됩니다.
그럼 union-find로 진실을 아는 사람들의 집합을 늘려가면 되는데요, 계산 편의를 위해 진실을 아는 0번 사람을 가상으로 추가해줍니다. 그러면 어떤 사람이 진실을 아는 집합에 있는지 아닌지 확인하려면 0번 사람의 parent를 확인해보면 됩니다.
각 파티마다 참가자들은 일심동체이기 때문에 파티 참가자들끼리 merge를 해줍니다. 이렇게 하면 나중엔 자연스럽게 진실을 아는 집합과, 모르는 집합(들)로 집합이 분리가 되겠죠? 확인할 때는 0번 사람의 parent랑 비교하면 됩니다.
#pragma GCC optimize ("Ofast")
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
int n, m;
int parent[51];
void init() {
for (int i = 0; i < n; ++i)
parent[i] = i;
}
int find(int u) {
if (u == parent[u]) return u;
return parent[u] = find(parent[u]);
}
void merge(int u, int v) {
u = find(u), v = find(v);
if (u == v) return;
parent[u] = v;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n >> m;
++n;
init();
vector<bool> truth(n);
truth[0] = true;
int t;
cin >> t;
while (t--) {
int tmp;
cin >> tmp;
truth[tmp] = true;
}
for (int i = 1; i < n; ++i)
if (truth[i])
merge(0, i);
vector<vector<int>> parties(m);
for (auto& party : parties) {
int p;
cin >> p;
party.resize(p);
for (auto& i : party)
cin >> i;
for (int i = 1; i < p; ++i)
merge(party[0], party[i]);
}
int counter = 0;
for (auto& party : parties) {
if (find(party[0]) != find(0))
++counter;
}
cout << counter << '\n';
return 0;
}
유니온파인드를 한 2주만에 짰더니 find 구현할 때 실수를 했었습니다. find 함수에서 return parent[u] = find(u)로 썼더니 오랜만에 스택오버플로 오류를 봤습니다;
반응형
'Online Judge > 백준' 카테고리의 다른 글
[백준][C++] 1089: 엘리베이터 (0) | 2020.07.03 |
---|---|
[백준][C++] 4836: 춤 (0) | 2020.07.02 |
[백준][C++] 1036: 36진수 (0) | 2020.06.24 |
[백준][C++] 18119: 단어 암기 (0) | 2020.06.21 |
[백준][C++] 17081: RPG Extreme (4) | 2020.06.16 |