BOJ

[백준] 1043번 거짓말 - C++

Union Find

Posted by dongjune on November 4, 2020

문제

1043 거짓말

풀이

Union Find 알고리즘을 활용하여 풀 수 있는 문제이다.
같은 파티에 참여한적 있는 사람들은 모두 같은 집합에 포함 되게 한다. 즉 같은 부모 노드를 가리키도록 한다.
만약 어떤 파티에 참여 한 사람이 이야기를 아는 사람과 같은 집합에 있다면 그 파티는 거짓말을 할 수 없는 파티이다.
자세한 내용은 소스코드의 주석을 통해 살펴 보자.

소스 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <iostream>
#include <vector>

using namespace std;

int n, m, k;
int parent[51];
vector<int> knowing; // 이야기를 아는 사람 벡터
vector<vector<int>> party(50); // party 참여 명단

int Find(int x)
{
    if (parent[x] == x)
        return x;
    return x = Find(parent[x]);
}

void Union(int x, int y)
{
    x = Find(x);
    y = Find(y);
    parent[x] = y;
}

void input()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    // n,m,k 입력
    cin >> n >> m >> k;
    // parent 초기화
    for (int i = 1; i <= n; i++)
        parent[i] = i;
    int x;
    // 이야기 아는사람 입력
    while (k--)
    {
        cin >> x;
        knowing.push_back(x);
    }
    // party 명단 입력
    int p, num, prev;
    for (int i = 0; i < m; i++)
    {
        cin >> p;
        for (int j = 0; j < p; j++)
        {
            // 같은 파티에 참여한 사람들을 같은 집합으로 합치는 과정
            if (j >= 1)
            {
                prev = num; 
                cin >> num;
                Union(prev, num);
            }
            else
                cin >> num;
            party[i].push_back(num);
        }
    }
}

int answer()
{
    int res = m;
    for (const auto &people : party) // 파티 순회
    {
        bool flag = false;
        for (const auto &person : people) // 파티의 참여자 순회
        {
            if (flag)
                break;
            for (const auto &know : knowing) // 이야기를 아는 사람 순회
            {
                // 파티의 참여자가 이야기를 아는 사람과 같은 집합(같은 파티에 참여한 적 있다)에 있다면 이 파티에서 거짓말을 할 수 없다. 그러므로 flag를 true로 바꿔주고 break 해준다.
                if (Find(person) == Find(know))
                {
                    flag = true;
                    break;
                }
            }
        }
        if (flag) // 파티에서 거짓말을 할 수 없다면
            res--;
    }

    return res;
}

int main()
{
    input();
    cout << answer() << '\n';
    return 0;
}