boj1717-풀이

boj.kr/1717 집합의 표현 (문제)

문제설명


0부터 n까지 n+1개의 독립된 집합으로 존재한다.
주어지는 연산에 따라 이 집합들을 합치고, 같은 집합에 속하는지 확인하는 문제
-> Union Find 구현문제

입력


n m
x a b (m개의 줄)

n : 원소의 수, m : 연산의 수
x : 연산종류, a, b : 합치려는 집합들의 두 원소

  1. x가 0일때, 주어진 두 수 a, b가 속한 집합을 합친다.
  2. x가 1일때, 주어진 두 수 a, b가 같은 집합에 속하는지 여부를 확인하여 YES/NO 출력

    출력


    1 연산에 대해
    두 원소가 같은 집합에 속한 경우 YES를 출력
    그렇지 않은 경우 NO를 출력

    예시 및 설명


    입력 (그림을 잘못그려서 원소갯수를 하나 늘렸다.. 7->8)

    8 8
    0 1 3
    1 1 7
    0 6 7
    1 7 1
    0 3 7
    0 2 4
    0 1 1
    1 1 1
    

    출력

    NO
    NO
    YES
    
  3. 각각 독립된 집합으로 존재
    // 상태
    rank[8] = {1, 1, 1, 1, 1, 1, 1, 1} 
    parent[8] = {0, 1, 2, 3, 4, 5, 6, 7}
    

    1

  4. 1과 3이 속한 집합을 합침 (union-by-rank에 의해 1의 rank 증가)
  5. 1과 7이 같은 집합이 아님 -> NO
    // 코드
    Union(1, 3)
    cout << (Find(1) == Find(7) ? "YES" : "NO")
    // 상태
    rank[8] = {1, 2, 1, 1, 1, 1, 1, 1}
    parent[8] = {0, 1, 2, 1, 4, 5, 6, 7}
    

    2

  6. 6과 7이 속한 집합을 합침 (union-by-rank에 의해 6의 rank 증가)
  7. 7과 1이 같은 집합이 아님 -> NO
    // 코드
    Union(6, 7)
    cout << (Find(7) == Find(1) ? "YES" : "NO")
    // 상태
    rank[8] = {1, 2, 1, 1, 1, 1, 2, 1}
    parent[8] = {0, 1, 2, 1, 4, 5, 6, 6}
    

    3

  8. 3과 7이 속한 집합을 합침 (union-by-rank에 의해 1의 rank 증가)
    3이 속한집합의 대표요소(1)와
    7이 속한집합의 대표 요소(6)를 연결
    // 코드
    Union(6, 7)
    // 상태
    rank[8] = {1, 3, 1, 1, 1, 1, 2, 1}
    parent[8] = {0, 1, 2, 1, 4, 5, 1, 6}
    

    4

  9. 2와 4가 속한 집합을 합침 (union-by-rank에 의해 2의 rank 증가)
  10. 1과 1이 속한 집합을 합침 (동일한 원소끼리 합치는 것은 무시)
  11. 1과 1이 같은 집합에 속했는지 확인 (동일한 원소는 확인할필요 없음) -> YES
    // 코드
    Union(2, 4)
    if(a != b) Union(1,1)
    // 상태
    rank[8] = {1, 3, 1, 1, 1, 1, 2, 1}
    parent[8] = {0, 1, 2, 1, 4, 5, 1, 6}
    

    4

풀이


이 문제에서는 딱히 풀이라 할 것은 없고,
각각의 집합으로 초기화하고, 그룹으로 묶는 과정을 보고 유니온 파인드라는 것을 빨리 알아차리면 된다.

기본 구현


아무런 최적화가 들어가지 않은 Union Find를 구현한 코드

#include <iostream>
#include <algorithm>
using namespace std;
#define NMAX 1000001
int parent[NMAX];
int n, m, x, a, b;
int Find(int p){
    if(parent[p] == p) return p;
    return Find(parent[p]);
}
void Union(){
    a = Find(a); b = Find(b);
    if(a == b) return;
    parent[b] = a;
}
int main(){
    ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> m;
    for(int i = 0; i <= n; ++i) {parent[i] = i;} // parent, rank 초기화
    while(m--){
        cin >> x >> a >> b;
        if(x)
            cout << (a == b || Find(a) == Find(b) ? "YES\n" : "NO\n");
        else
            Union();
    }
    return 0;
}

union-by-rank 추가 구현


기본구현 + union-by-rank 구현을 추가한 코드

#include <iostream>
#include <algorithm>
using namespace std;
#define NMAX 1000001
int parent[NMAX], rank_[NMAX];
int n, m, x, a, b;
int Find(int p){
    if(parent[p] == p) return p;
    return Find(parent[p]);
}
void Union(){
    a = Find(a); b = Find(b);
    if(a == b) return;
    if(rank_[a] < rank_[b]) swap(a, b);
    else if(rank_[a] == rank_[b]) ++rank_[a];
    parent[b] = a;
}
int main(){
    ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> m;
    for(int i = 0; i <= n; ++i) {parent[i] = i; rank_[i] = 1;} // parent, rank 초기화
    while(m--){
        cin >> x >> a >> b;
        if(x)
            cout << (a == b || Find(a) == Find(b) ? "YES\n" : "NO\n");
        else
            Union();
    }
    return 0;
}

union-by-rank + 경로압축(path compression)추가 구현, 최종코드


기본구현 + union-by-rank + path compression 을 추가한 코드

#include <iostream>
#include <algorithm>
using namespace std;
#define NMAX 1000001
int parent[NMAX], rank_[NMAX];
int n, m, x, a, b;
int Find(int p){
    if(parent[p] == p) return p;
    return parent[p] = Find(parent[p]);
}
void Union(){
    a = Find(a); b = Find(b);
    if(a == b) return;
    if(rank_[a] < rank_[b]) swap(a, b);
    else if(rank_[a] == rank_[b]) ++rank_[a];
    parent[b] = a;
}
int main(){
    ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> m;
    for(int i = 0; i <= n; ++i) {parent[i] = i; rank_[i] = 1;} // parent, rank 초기화
    while(m--){
        cin >> x >> a >> b;
        if(x)
            cout << (a == b || Find(a) == Find(b) ? "YES\n" : "NO\n");
        else
            Union();
    }
    return 0;
}

댓글남기기