[ 백준 ] 1197 / 최소 스패닝 트리

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
46/228
post-thumbnail

# Appreciation

/*
 * Problem :: 1197 / 최소 스패닝 트리
 *
 * Kind :: Graph
 *
 * Insight
 * - 최소 스패닝 트리(MST, Minimum Spanning Tree)
 *   MST 간선의 개수 = MST 정점의 개수 - 1
 *   + Kruskal 알고리즘으로 구하자
 *     # 사이클 확인은 Union-Find 알고리즘으로 해결하자
 *       -> 사이클이 만들어지려면
 *          같은 집합에 속한 간선을 추가해야 하는데
 *          이 경우 Find 알고리즘으로 막을 수 있다
 *
 * Point
 * - 다음에 만나는 최소 스패닝 트리 문제는
 *   Prim 알고리즘으로 해결하자
 *   + 왜 지금 안하세요?
 *     # 귀찮아서...
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <vector>
#include <queue>
#include <tuple>
#include <algorithm>

using namespace std;

#define endl '\n'

// Set up : Global Variables
struct Edge { int a, b, c; };
int P[10000+1], R[10000+1];

// Set up : Functions Declaration
int find(int x);
void merge(int x, int y);
bool operator > (Edge u, Edge v);


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    int V, E;
    cin >> V >> E;
    priority_queue<Edge, vector<Edge>, greater<>> pq;
    for (int i=0; i<E; i++) {
        int A, B, C;
        cin >> A >> B >> C;
        pq.push({A, B, C});
    }

    // Process
    /* Union-Find 알고리즘을 위한 전처리 */
    for (int i=1; i<=V; i++) {
        P[i] = i;
        R[i] = 1;
    }

    /* cnt = 현재 MST 간선의 개수
     * cnt 가 V-1 이면 모든 정점이 연결되었다는 것을 뜻함
     * 즉, MST 가 완성되었음을 가리킴 */
    int cnt = 0, ans = 0;
    while (cnt < V-1) {
        /* 우선순위 큐에 남은 간선들 중 가중치가 가장 작은 간선 추출 */
        auto [A, B, C] = pq.top();
        pq.pop();

        /* 서로 이미 연결된 정점이면 넘어감 */
        if (find(A) == find(B)) continue;
        merge(A, B); /* 정점 연결 */
        ans += C; /* 가중치 증가 */
        cnt++; /* 간선 개수 증가 */
    }

    // Control : Output
    cout << ans << endl;
}

// Helper Functions
bool operator > (Edge u, Edge v)
/* 구조체 Edge 비교를 위한 연산자 오버로딩 */
{
    return make_tuple(u.c, u.b, u.a) > make_tuple(v.c, v.b, v.a);
}

int find(int x)
/* Union-Find 알고리즘의 Find 함수 */
{
    if (P[x] == x) return x;
    return P[x] = find(P[x]);
}

void merge(int x, int y)
/* Union-Find 알고리즘의 Union 함수 */
{
    x = find(x);
    y = find(y);
    if (x == y) return;

    if (R[x] < R[y]) swap(x, y);
    P[y] = x;
    if (R[x] == R[y]) R[x]++;
}
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글