컴퓨터과학/알고리즘_PS
[백준] 1043 - 거짓말
MG#
2022. 5. 16. 13:55
https://www.acmicpc.net/problem/1043
1043번: 거짓말
지민이는 파티에 가서 이야기 하는 것을 좋아한다. 파티에 갈 때마다, 지민이는 지민이가 가장 좋아하는 이야기를 한다. 지민이는 그 이야기를 말할 때, 있는 그대로 진실로 말하거나 엄청나게
www.acmicpc.net
이 문제의 요점은 같은 파티에 한 번이라도 속한 사람은 전부 통한다는 것이다. 예를 들어 1번이 진실을 알고 있고 2번이 한번이라도 1번과 같은 파티에 참석했으면 순서에 상관없이 다른 파티에서는 2번은 진실을 아는 사람처럼 행동하게 된다. 그렇기에 이 문제는 한 번이라도 같은 파티에 참석해봤냐 안 해봤냐 나누는 문제로 Union-Find 알고리즘을 사용하면 된다.
더 자세히 말하자면 각 파티당 참여하는 인원을 다 Union 해준다. 그렇게하면 한 번이라도 파티에서 만난 적 있는 사람들로만 이루어진 그룹으로 나뉘어지게 된다. 그리고 각 파티당 참여인원을 loop 돌려 known(진실을 아는 사람)과 비교해주고 같은 그룹이면 답에서 뺀다. 그렇지 않으면 같은 파티에 한 번도 만나지 않기에 거짓말을 해도 된다.
#include <iostream>
#include <vector>
#define MAX 51
using namespace std;
vector<int> party[MAX], known;
int par[MAX];
int n, m, tmp, num, ans;
int Find(int a) {
if (a == par[a]) return a;
return par[a] = Find(par[a]);
}
void Union(int a, int b) {
a = Find(a);
b = Find(b);
par[b] = a;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> tmp;
for (int i = 1; i <= n; i++)
par[i] = i;
for (int i = 0; i < tmp; i++) {
cin >> num;
known.push_back(num);
}
for (int i = 0; i < m; i++) {
cin >> num;
for (int j = 0; j < num; j++) {
cin >> tmp;
party[i].push_back(tmp);
Union(party[i][0], party[i][j]);
}
}
ans = m;
for (int i = 0; i < m; i++) {
bool flag = false;
for (int j : party[i]) {
if (flag) break;
for (int k : known) {
if (Find(j) == Find(k)) {
flag = true;
break;
}
}
}
if (flag) ans--;
}
cout << ans << "\n";
return 0;
}