www.acmicpc.net/problem/1043

 

1043번: 거짓말

지민이는 파티에 가서 이야기 하는 것을 좋아한다. 파티에 갈 때마다, 지민이는 지민이가 가장 좋아하는 이야기를 한다. 지민이는 그 이야기를 말할 때, 있는 그대로 진실로 말하거나 엄청나게 �

www.acmicpc.net


  • 진실을 알고 있는 사람이 속한 파티의 참가자들은 모두 진실을 알게 된다.
  • 그 참가자들이 속한 다른 파티 역시 모두 진실을 알게 된다.
  • 파티의 참가자들을 하나의 그룹으로 묶는다.
  • 사람을 기준으로 그룹을 묶게 되면, 다른 파티와 중복된 참가자가 있으면 모두 같은 그룹으로 묶이게 된다.
  • 모든 그룹을 나눈 뒤, 처음에 입력해준 진실을 아는 사람들의 그룹과 파티의 멤버들을 전부 비교해나가면, 해당 파티가 진실을 아는 사람들의 그룹인지 알 수 있다.
  • 말로만 설명하기가 조금 까다로운데, 유니온 파인드를 찾아보면 더 명확하게 이해할 수 있다.

#include <iostream>
#include <vector>

using namespace std;

int n, m, ans;
vector<int> know;               // 입력으로 주어진, 기존에 알고있던 사람들
vector<vector<int>> party;      // 각 파티에 참여하는 사람들
int parent[51];                 // 모든 사람들을 그룹화시키는 배열
int num, temp;

int find(int idx)               // 해당 사람의 최종 그룹을 반환 (루트 노드)
{
    if(idx != parent[idx]) idx = find(parent[idx]); // 루트노드가 아닐 시 해당 노드의 부모 노드로 재귀 호출
    return idx;
}

void union_(int x, int y)       // 두 사람을 그룹화시킴 (루트 노드를 같게 만듦)
{
    x = find(x);
    y = find(y);
    parent[y] = x;
}

int main(void)
{
    cin >> n >> m;
    cin >> num;

    for(int i = 0 ; i < num ; i++)
    {
        cin >> temp;
        know.push_back(temp);
    }
    for(int i = 1 ; i <= n ; i++) parent[i] =i;

    for(int i = 0 ; i < m ; i++)                    // 모든 파티들에 대해서 서로 연결시키는 과정
    {
        cin >> temp;
        vector<int> member;
        cin >> num;
        member.push_back(num);
        int prev;
        for(int k = 1 ; k < temp ; k++)             // 각 파티의 멤버들을 같은 그룹으로 묶어놓음
        {
            prev = num;
            cin >> num;
            union_(prev, num);                      // 묶는 과정에서 다른 파티원과도 연결될 수 있음
            member.push_back(num);
        }
        party.push_back(member);
    }
    for(int i = 0 ; i < know.size() ; i++)
    {
        know[i] = find(know[i]);
    }

    for(int i = 0 ; i < m ; i++)                    // 모든 파티들을 돌면서
    {
        bool able = true;
        for(int j = 0 ; j < party[i].size() ; j++)  // 각 파티의 멤버들 중
        {
            int root = find(party[i][j]);
            for(int k = 0 ; k < know.size() ; k++)
            {
                if(root == know[k])                 // 한명이라도 진실을 알고있는 사람과 같은 그룹에 있다면
                {
                    able = false;                   // 해당 파티를 세지 않음
                    break;
                }
            }
            if(able == false) break;
        }
        if(able) ans++;                             // 해당 파티에 아무도 진실을 아는 그룹과 엮여있지 않을 때에만 카운트
    }
    cout << ans << endl;
}

'PS > BOJ' 카테고리의 다른 글

[백준] 1916.cpp : 최소비용 구하기  (0) 2020.08.21
[백준] 1753.cpp : 최단경로  (0) 2020.08.20
[백준] 1912.cpp : 연속합  (0) 2020.08.16
[백준] 10844.cpp : 쉬운 계단 수  (0) 2020.08.15
[백준] 2003.cpp : 수들의 합 2  (0) 2020.08.14

+ Recent posts