[자료 구조] 최소 신장 트리(MST) 개념 및 구현(Kruscal, Prim)

2021. 6. 3. 23:15·Major/Data Structure
728x90

1.  최소 신장 트리

- 연결된 그래프 G(V.E)의 신장 트리란, 그래프 내의 모든 정점을 포함하는 트리다.

- 이 트리는 모든 정점들이 연결되어 있어야 하고, 사이클이 없어야 한다.

- 에지에 가중치가 주어진 그래프 G에서 G의 신장 트리 중에 에지 가중치 합이 최소가 되는 신장 트리를 

  최소 신장트리라고 한다.

 

2. 최소 신장 트리 알고리즘

1) 크루스칼(Kruskal)의 알고리즘

- 크루스칼의 알고리즘은 탐욕적인(greedy method) 방법을 이용한다. 

- 탐욕적인 방법이란 선택할 때마다 그 순간 가장 좋다고 생각 되는 것을 선택함으로써 최종적인 해답에 도달하는 방법

 

👉 알고리즘

- 가중치가 최소인 간선을 추가해가며 트리를 만들어 간다.

- 만약에 간선을 추가해서 사이클이 만들어 진다면 그 간선은 제외한다.

- 간선의 개수가 N - 1(N은 노드의 개수)이되면 모든 노드가 연결이 된 것이므로 종료한다.

 

- 그림을 보면서 이해하면 쉽다.

 

- 이 알고리즘을 구현하기 위해선 유니온 파인드 자료구조와 힙을 이용해야 한다.

=> [Algorithm] 유니온 파인드(Union-Find) 개념, 코드(C++) (tistory.com)

 

 

👉 구현

- 최소 힙과 유니온파인드를 이용하여 구현함.

- 최소 힙은 직접 구현하지 않고 STL을 이용함

#include <iostream>
#include <algorithm> 
#include <queue>
#include <vector>
using namespace std;

int parent[3001];

struct element {
	int v1, v2, key;
};

//가중치를 기준으로 오름차순으로 정렬해주는 오퍼레이터
struct cmp {
	bool operator()(element x, element y) {
		return x.key > y.key;
	}
};
int myfind(int x) {
	if (parent[x] == x) return x;
	return parent[x] = myfind(parent[x]);
}

void myunion(int a, int b) {
	a = myfind(a);
	b = myfind(b);
	if (a != b) {
		parent[b] = a;
	}
}

bool same_parent(int x, int y) {
	x = myfind(x);
	y = myfind(y);
	if (x == y) return true;
	else return false;
}


int main() {
	priority_queue<element, vector<element>, cmp>arr;
	int n, m; //정점, 엣지
	cin >> n >>m;
	for (int i = 0; i < m; i++) {
		int a, b, c; //v1, v2, key
		cin >> a >> b >> c;
		arr.push({ a, b, c});
	}
	
	for (int i = 0; i < n; i++) {
		parent[i] = i;
	}

	int ans = 0; //가중치합
	while (!arr.empty()) {
		if (!same_parent(arr.top().v1, arr.top().v2)) {
			ans += arr.top().key;
			myunion(arr.top().v1, arr.top().v2);
		}
		arr.pop();
	}

	cout << ans;
	return 0;

}

- 시간 복잡도 :  O(mlogm) // 가중치를 정렬하는데 걸리는 시간(힙정렬) + 유니온 파인드 시간

 

2) 프림(Prim) 알고리즘

- 그래프 𝐺의 정점 하나로 이루어진 부분 트리에서 시작하여, 각 반복 과정마다 이미 구성된 부분 트리에 정점과 에지를 하나씩 추가한다.

- 이 때 부분 트리에 속한 정점과 인접한 정점 사이의 에지 중 가중치가 최소인 에지를 선택한다.

 

- 그림을 보면 이해하기 쉽다.

 

👉 알고리즘

1 임의의 정점을 선택하여 비어있는 T 에 포함 (이제 T 는 노드가 한개인 트리) 

2 T 에 있는 노드와 T 에 없는 노드 사이의 간선 중 가중치가 최소인 간선을 찾는다. 

3 찾은 간선이 연결하는 두 노드중, T 에 없던 노드를 T 에 포함시킨다.

4 모든 노드가 T 에 포함될때 까지 2,3 을 반복 해준다

 

👉 구현

- 우선순위 큐(stl)을 이용하여 구현함

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

typedef pair<int, int> p; //인접정점, 가중치 저장하는 페어

bool visited[3001];
vector<p> v[3001];

void prim(int start){
    visited[start] = true;
    priority_queue<p, vector<p>, greater<p>> pq; //인접정점의 가중치들을 저장할 큐(오름차순)

    for (int i = 0; i < v[start].size(); i++){
        int next = v[start][i].first;
        int nextCost = v[start][i].second;
        pq.push(p(nextCost, next));
    }

    int ans = 0;

    while (!pq.empty()){
        int here = pq.top().second;
        int hereCost = pq.top().first;

        pq.pop();

        if (visited[here]) continue; //만약에 방문한거면 넘어감

        visited[here] = true;
        ans += hereCost;

        for (int i = 0; i < v[here].size(); i++){
            int next = v[here][i].first;
            int nextCost = v[here][i].second;
            pq.push(p(nextCost, next));
        }
    }

    cout << ans;
}

int main()
{
    int n, m; //정점, 엣지
    cin >> n >> m;
    for (int i = 0; i < m; i++){
        int a, b, c; //u, v, 가중치
        cin >> a >> b >> c;
        v[a].push_back(p(b, c)); //정점 a의 인접정점은 b고 가중치는 c
        v[b].push_back(p(a, c)); //정점 b의 인접정점은 a고 가중치는 c
    }

    prim(1);

    return 0;
}

- 시간복잡도 : O(n^2)

728x90
저작자표시 비영리 (새창열림)

'Major > Data Structure' 카테고리의 다른 글

[C언어로 쉽게 풀어쓴 자료구조] 03장 - 연습문제  (0) 2021.08.10
[자료 구조] 최단 경로 - 다익스트라(Dijkstra) 알고리즘 개념 및 구현 *  (0) 2021.06.07
[자료구조] 그래프 순회(Graph Traversal) 개념 및 구현  (0) 2021.06.02
[자료구조] 그래프 개념 및 구현(인접 리스트)  (0) 2021.05.31
[C언어로 쉽게 풀어쓴 자료구조] 02장 순환 - 연습문제  (0) 2021.05.15
'Major/Data Structure' 카테고리의 다른 글
  • [C언어로 쉽게 풀어쓴 자료구조] 03장 - 연습문제
  • [자료 구조] 최단 경로 - 다익스트라(Dijkstra) 알고리즘 개념 및 구현 *
  • [자료구조] 그래프 순회(Graph Traversal) 개념 및 구현
  • [자료구조] 그래프 개념 및 구현(인접 리스트)
BeNI
BeNI
코딩하는 블로그
  • BeNI
    코딩못하는컴공
    BeNI
  • 전체
    오늘
    어제
    • Menu (253)
      • My profile (1)
      • 회고 | 후기 (8)
      • Frontend (65)
        • Article (11)
        • Study (35)
        • 프로그래머스 FE 데브코스 (19)
      • Backend (0)
      • Algorithm (58)
        • Solution (46)
        • Study (12)
      • Major (111)
        • C&C++ (23)
        • Java (20)
        • Data Structure (14)
        • Computer Network (12)
        • Database (15)
        • Linux (6)
        • Architecture (3)
        • Lisp (15)
        • OS (1)
        • Security (2)
      • etc (2)
  • 링크

    • 깃허브
    • 방명록
  • 인기 글

  • 최근 댓글

  • 최근 글

  • 태그

    프로그래머스
    react
    데브코스
    Algorithm
    백준
    C++
    lisp
    리팩토링
    자료구조
    파일처리
  • hELLO· Designed By정상우.v4.10.2
BeNI
[자료 구조] 최소 신장 트리(MST) 개념 및 구현(Kruscal, Prim)
상단으로

티스토리툴바