ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 최소 신장 트리 (Minimun Spanning Tree) MST, swexpert 1251 하나로
    전공 지식/자료구조 && 알고리즘 2018. 10. 11. 14:05

    최소 신장 트리 MST



    Spanning Tree 는 연결 Graph 이자, 무향그래프의 SubGraph 로 모든 정점을 포함하고 사이클이 없는 그래프를 뜻합니다.

    Spanning Tree 중 간선의 가중치의 합이 최소인 것을 MST 라고 합니다. 


    MST 를 찾아내는 방법은


    1. 프림 알고리즘 (Prim's Algorithm)

    2. 크루스칼 알고리즘 (Kruskal's Algorithm)

    이 있습니다.


    프림 알고리즘 (Prim's Algorithm)

    - Dense 한 그래프에서 MST를 찾을때 좋은 알고리즘으로 시간복잡도는 PQ의 구현에 따라 달라집니다. 

       PQ를 Heap으로 구현하였을 때, O(ElogV) 의 시간 복잡도를 가질 수 있습니다.

    (a) 초기 가중치가 있는 무향 그래프 입니다.

    (b) 시작 정점을 선택합니다. -> 시작 정점은 아무 정점을 선택할 수 있습니다.

    (c) A 정점에서 연결된 간선 중 가장 가중치가 작은 간선을 선택합니다. -> 이 부분을 PQ를 이용하여 빠르게 찾아낼 수 있습니다.

    (d) 가장 가중치가 작은 간선을 선택한 후, 연결된 정점을 Tree Set에 추가시켜 줍니다. 뿐만아니라 추가된 정점에 연결된 간선을 PQ에 추가시켜 줍니다.

    (e-f) 이후 이 과정을 반복하여 MST를 찾을 수 있습니다. 만약 이미 Tree Set에 추가된 정점이라면 Cycle이 생기기 때문에 연결하지 않습니다.





    크루스칼 알고리즘 (Kruskal's Algorithm)

    - Spase 한 그래프에서 MST를 찾을 때, 좋은 알고리즘으로 O(ElogE) 의 시간복잡도를 가집니다.

    - 많은 사람들이 사용하고 있는 Union-Find 알고리즘을 사용하여 크루스칼 알고리즘을 구현할 수 있습니다.


    모든 Vertex를 Tree라고 하고, 모든 Edge 중에 가장 작은 Edge를 선택합니다. 

    만약 두 Vertex가 같은 Tree라면 Cycle이 생기기 때문에 선택하지 않고, 다른 트리라면 선택하여 Union을 해줄 수 있습니다.


    1. 2.  

    3.4.  

    5.6. 


    1) 모든 정점을 TreeSet으로 설정합니다.

    2) 모든 정점을 PQ에 넣어 가중치가 작은 순으로 정렬합니다.

    3) 가중치가 가장 작은 간선의 양 끝 정점을 연결하여 TreeSet을 만들어줍니다.

    4~5) 이와 같은 과정을 반복합니다. 만약 같은 Tree Set에 추가된 정점이라면 Cycle이 생기기 때문에 연결하지 않습니다.

    6) 마지막으로 완성된 MST에 연결된 간선의 정보입니다.


    SWEXPERT 1251_ 하나로 를 MST를 이용하여 해결 할 수 있습니다. 크루스칼 알고리즘을 사용하여 문제를 해결하였습니다.

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <map>
    #include <vector>
    #include <stack>
    #include <queue>
    using namespace std;
    
    int n;
    double e;
    long long arr[1010][1010];
    long long parents[1010];
    long long find(long long first) {
        if(parents[first] == first) {
            return first;
        }
        else {
            return parents[first] = find(parents[first]);
        }
    }
    bool Union(long long first, long long second) {
    
        long long pF = find(first);
        long long pS = find(second);
        if(pF == pS)
            return true;
        
        parents[pF] = pS;
        return false;
    }
    
    int main() {
        int t;
        scanf("%d",&t);
        for(int test = 1; test <= t; test++) {
            priority_queue<pair<long long, pair<long long ,long long>>> pq;
            memset(arr, 0, sizeof(arr));
            memset(parents, 0, sizeof(parents));
            scanf("%d",&n);
            vector<long long>x,y;
            x.resize(n);
            y.resize(n);
            for(int i=0;i<n;i++) {
                scanf("%lld",&x[i]);
            }
            for(int i=0;i<n;i++) {
                scanf("%lld",&y[i]);
            }
            scanf("%lf",&e);
            for(long long i=0;i<n;i++)
                parents[i] = i;
            for(long long i=0;i<n;i++) {
                for(long long j=i+1;j<n;j++) {
                    arr[i][j] = ((x[j] - x[i]) * (x[j] - x[i]) +  (y[j] - y[i]) * (y[j] - y[i]));
                    arr[j][i] = arr[i][j];
                    pq.push(make_pair(-arr[i][j],make_pair(i,j)));
                }
            }
            double size = 0;
            
            int cnt = 0;
            while(!pq.empty()) {
                if(cnt == n-1)
                    break;
                long long dist = -pq.top().first;
                long long first = pq.top().second.first;
                long long second = pq.top().second.second;
                pq.pop();
                bool isUnion = Union(first, second);
                
                if(isUnion)
                    continue;
                
                size += dist;
                cnt++;
            }
            size = (size * e);
    
            printf("#%d %0.lf\n",test, size);
            
        }
        
    }
    


    댓글