πŸ”— Union-Find μ•Œκ³ λ¦¬μ¦˜ κ΅¬ν˜„ 예제 (C μ–Έμ–΄)

μ΄μž¬ν™˜Β·2024λ…„ 9μ›” 24일
0

이번 ν¬μŠ€νŒ…μ—μ„œλŠ” Union-Find μ•Œκ³ λ¦¬μ¦˜μ„ C μ–Έμ–΄λ‘œ κ΅¬ν˜„ν•œ μ˜ˆμ‹œλ₯Ό μ†Œκ°œν•˜κ² μŠ΅λ‹ˆλ‹€. 이 μ•Œκ³ λ¦¬μ¦˜μ€ κ·Έλž˜ν”„ λ¬Έμ œμ—μ„œ μ„œλ‘œμ†Œ 집합을 관리할 λ•Œ μœ μš©ν•˜κ²Œ μ‚¬μš©λ˜λ©°, 주둜 사이클 κ²€μΆœμ΄λ‚˜ μ΅œμ†Œ μ‹ μž₯ 트리λ₯Ό 찾을 λ•Œ 많이 ν™œμš©λ©λ‹ˆλ‹€.

μ•„λž˜ μ˜ˆμ œμ—μ„œλŠ” 두 가지 μ£Όμš” 연산인 Find와 Union을 톡해 집합을 κ΄€λ¦¬ν•˜κ³ , λ§ˆμ§€λ§‰μ— 두 λ…Έλ“œκ°€ 같은 집합에 속해 μžˆλŠ”μ§€λ₯Ό νŒλ³„ν•©λ‹ˆλ‹€.

πŸ“‚ μ½”λ“œ μ„€λͺ…

#include<stdio.h>

int n, parent[1001];  // λ…Έλ“œ κ°œμˆ˜μ™€ λΆ€λͺ¨ λ°°μ—΄ μ„ μ–Έ

// πŸ•΅οΈβ€β™‚οΈ Find ν•¨μˆ˜: ν•΄λ‹Ή λ…Έλ“œκ°€ μ†ν•œ μ§‘ν•©μ˜ λŒ€ν‘œ(루트) λ…Έλ“œλ₯Ό μ°ΎλŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.
int Find(int v)
{
    if (parent[v] == v)
        return v;  // 루트 λ…Έλ“œμ΄λ©΄ 자기 μžμ‹ μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.
    else
        return parent[v] = Find(parent[v]);  // 경둜 μ••μΆ•μœΌλ‘œ λΆ€λͺ¨λ₯Ό 루트둜 κ°±μ‹ ν•˜λ©° λ°˜ν™˜ν•©λ‹ˆλ‹€.
}

// πŸ”— Union ν•¨μˆ˜: 두 집합을 ν•©μΉ˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.
void Union(int x, int y)
{
    x = Find(x);  // x의 루트λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.
    y = Find(y);  // y의 루트λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.

    if (x != y)
        parent[x] = y;  // 두 λ£¨νŠΈκ°€ λ‹€λ₯΄λ©΄ yλ₯Ό x의 λΆ€λͺ¨λ‘œ μ„€μ •ν•©λ‹ˆλ‹€.
}

// πŸ› οΈ μ΄ˆκΈ°ν™” ν•¨μˆ˜: λͺ¨λ“  λ…Έλ“œμ˜ λΆ€λͺ¨λ₯Ό 자기 μžμ‹ μœΌλ‘œ μ„€μ •ν•©λ‹ˆλ‹€.
void Set()
{
    int i;
    for (i = 1; i <= n; i++)
        parent[i] = i;  // μ²˜μŒμ—λŠ” 각 λ…Έλ“œκ°€ 자기 μžμ‹ μ„ λΆ€λͺ¨λ‘œ κ°€μ§‘λ‹ˆλ‹€.
}

int main(void)
{
    int m, i, a, b;

    scanf("%d %d", &n, &m);  // λ…Έλ“œ κ°œμˆ˜μ™€ μ—°μ‚° 횟수λ₯Ό μž…λ ₯λ°›μŠ΅λ‹ˆλ‹€.
    Set();  // μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€.

    // πŸ”„ m번의 Union 연산을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.
    for (i = 0; i < m; i++)
    {
        scanf("%d %d", &a, &b);
        Union(a, b);  // a와 bλ₯Ό 같은 μ§‘ν•©μœΌλ‘œ ν•©μΉ©λ‹ˆλ‹€.
    }

    // ❓ a와 bκ°€ 같은 집합에 μ†ν•˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.
    scanf("%d %d", &a, &b);
    if (Find(a) == Find(b))
        printf("YES\n");  // 같은 집합에 μ†ν•˜λ©΄ YESλ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€.
    else
        printf("NO\n");  // 그렇지 μ•ŠμœΌλ©΄ NOλ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€.

    return 0;
}

πŸ“š μ£Όμš” ν•¨μˆ˜ μ„€λͺ…

1️⃣ Find(int v)

  • 이 ν•¨μˆ˜λŠ” μž¬κ·€λ₯Ό μ‚¬μš©ν•˜μ—¬ ν•΄λ‹Ή λ…Έλ“œ vκ°€ μ†ν•œ μ§‘ν•©μ˜ 루트 λ…Έλ“œλ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.
  • 경둜 μ••μΆ• 기법을 μ‚¬μš©ν•˜μ—¬ 탐색 νš¨μœ¨μ„±μ„ λ†’μž…λ‹ˆλ‹€. 즉, νƒμƒ‰ν•˜λ©΄μ„œ λ§Œλ‚˜λŠ” λͺ¨λ“  λ…Έλ“œκ°€ 루트 λ…Έλ“œλ₯Ό 직접 가리킀도둝 κ°±μ‹ ν•©λ‹ˆλ‹€. πŸš€

2️⃣ Union(int x, int y)

  • 두 λ…Έλ“œ x와 yλ₯Ό 같은 μ§‘ν•©μœΌλ‘œ ν•©λ³‘ν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€.
  • 두 λ…Έλ“œμ˜ λ£¨νŠΈκ°€ λ‹€λ₯΄λ©΄ x의 루트λ₯Ό y의 루트둜 κ°±μ‹ ν•˜μ—¬ ν•©μΉ©λ‹ˆλ‹€. πŸ”—

3️⃣ Set()

  • λͺ¨λ“  λ…Έλ“œμ˜ λΆ€λͺ¨λ₯Ό 자기 μžμ‹ μœΌλ‘œ μ΄ˆκΈ°ν™”ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€. 초기 μƒνƒœμ—μ„œλŠ” 각 λ…Έλ“œκ°€ 자기 μžμ‹ μ΄ λ£¨νŠΈμž…λ‹ˆλ‹€. 🌱

πŸ§ͺ μ‹€ν–‰ μ˜ˆμ‹œ

μž…λ ₯:
5 4
1 4
2 4
3 4
4 5
1 5

좜λ ₯:
YES

μ„€λͺ…

  1. 6개의 λ…Έλ“œκ°€ 있고 4번의 Union 연산을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.
  2. λ§ˆμ§€λ§‰μœΌλ‘œ 1κ³Ό 5κ°€ 같은 집합에 속해 μžˆλŠ”μ§€ 확인할 λ•Œ, YESκ°€ 좜λ ₯λ©λ‹ˆλ‹€. πŸŽ‰

πŸ“ κ²°λ‘ 

Union-Find μ•Œκ³ λ¦¬μ¦˜μ€ μ„œλ‘œμ†Œ 집합을 효율적으둜 관리할 수 μžˆλŠ” λŒ€ν‘œμ μΈ μ•Œκ³ λ¦¬μ¦˜μž…λ‹ˆλ‹€. Find와 Union 연산을 톡해 집합을 λ³‘ν•©ν•˜κ³ , 경둜 μ••μΆ• κΈ°λ²•μœΌλ‘œ μ„±λŠ₯을 μ΅œμ ν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€. πŸ’‘

κ·Έλž˜ν”„ νƒμƒ‰μ΄λ‚˜ 사이클 κ²€μΆœ λ¬Έμ œμ—μ„œ 자주 μ‚¬μš©λ˜λ‹ˆ κΌ­ μ΅ν˜€λ‘μ‹œκΈ° λ°”λžλ‹ˆλ‹€. 😎


❓ μΆ”κ°€ 질문

κΆκΈˆν•œ 점이 μžˆκ±°λ‚˜ μ½”λ“œμ— λŒ€ν•œ λ¬Έμ˜μ‚¬ν•­μ΄ μžˆμœΌμ‹œλ©΄ μ–Έμ œλ“ μ§€ λŒ“κΈ€λ‘œ λ‚¨κ²¨μ£Όμ„Έμš”! πŸ€—

0개의 λŒ“κΈ€