MST

2025. 4. 25. 13:02·알고리즘(코딩테스트)

참고자료

https://blog.encrypted.gg/1024

 

[실전 알고리즘] 0x1B강 - 최소 신장 트리

안녕하세요, 오늘 다룰 주제는 최소 신장 트리(Minimum Spanning Tree)라는 개념입니다. 보통 코딩 좀 치는 사람들 사이에서는 MST라고 많이들 부릅니다. 그런데 Spanning이나 신장 이 단어가 너무 낯설지

blog.encrypted.gg

 

1. 최소 스패닝(신장) 트리


신장 트리란

  • 주어진 방향성이 없는 그래프의 부분 그래프들 중에서 모든 정점을 포함하는 트리를 말한다.
  • 부분 그래프란 주어진 그래프에서 일부 정점과 간선만을 택해서 구성한 그래프를 말한다.
  • 참고) 트리는 무방향이면서 사이클이 없는 연결 그래프

그림 예시

  • 신장트리가 아닌 예시는 모든 정점을 포함하지 않거나, 사이클이 존재하기 때문에 신장 트리가 아니다.

최소 신장 트리

  • 신장 트리 중에서 간선의 "합이 최소"인 트리를 의미한다.
  • 최소신장트리는 동일한 그래프에서 한개가 아닐수 있다.

 

 

2. 구현 알고리즘


2 - 1. 크루스칼 알고리즘

가장 비용이 낮은 간선부터 시작해 간선을 크기 순으로 살펴보며, 서로 떨어져 있던 정점들을 합쳐나가는 방식

유니온 파인드 기법, 그리디 방식 사용

 

동작 방식

  • 간선의 크기를 오름차순으로 정렬, 제일 낮은 비용의 간선 선택
  • 현재 선택한 간선이 연결한 정점이 같은 그룹이라면 아무것도 하지않고 넘어감
  • 연결한 정점이 다른 그룹이라면, 같은 그룹으로 만들고 현재 선택한 간선을 최소신장트리에 추가
  • 최소신장트리에 v-1개의 간선이 추가되면 과정을 종료, 그렇지 않으면 다음으로 비용이 작은 간선을 선택한 후 위의 과정 반복

템플릿 코드 ( https://www.acmicpc.net/problem/1197 )

  • find와 diff_group 함수가 유니온 파인드 내용
  • 유니온 파인드를 통해 같은 그룹인지 아닌지를 체크

 

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

int v, e;
tuple<int, int, int> edge[100005]; //비용 정점1 정점2
vector<int> p(10005, -1);

int find(int x)
{
	if (p[x] < 0)
		return x;
	return p[x] = find(p[x]);
}

bool diff_group(int u, int v)
{
	u = find(u);
	v = find(v);

	if (u == v)
		return 0;
	if (p[u] == p[v])
		p[u]--;
	if (p[u] < p[v])
		p[v] = u;
	else
		p[u] = v;
	return 1;
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	
	cin >> v >> e;

	for (int i = 0; i < e; ++i)
	{
		int a, b, cost;
		cin >> a >> b >> cost;
		edge[i] = { cost,a,b };
	}

	sort(edge, edge + e);
	int cnt = 0;
	int ans = 0;

	for (int i = 0; i < e; ++i)
	{
		int cost, a, b;
		tie(cost, a, b) = edge[i];
		
		if (!diff_group(a, b))
			continue;
		ans += cost;
		cnt++;
		if (cnt == v - 1)
			break;
	}
	cout << ans;
}

 

2 - 2. 프림 알고리즘

동작 과정

  • 임의의 정점을 선택해 최소 신장 트리에 추가
  • 최소 신장 트리에 포함된 정점과 포함되지 않은 정점을 연결하는 간선 중 비용이 가장 작은 것을 최소 신장 트리에 추가
  • 최소신장트리에 간선이 v-1이 될때까지 반복

이 알고리즘을 구현하기 위해서는 우선순위큐를 사용하여, 효율적으로 구현해야 한다. (다익스트라와 유사한 방식)

 

템플릿 코드

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

int v, e;
vector<pair<int, int>> adj[10005]; //비용, 정점 번호
bool check[10005]; //최소신장트리에 포함된 정점
int cnt = 0;
int ans = 0;

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> v >> e;
	for (int i = 0; i < e; ++i)
	{
		int a, b, cost;
		cin >> a >> b >> cost;

		adj[a].push_back({ cost, b });
		adj[b].push_back({ cost, a });
	}

	priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, greater<tuple<int, int, int>> > pq;

	check[1] = 1; //1을 시작으로
	for (auto nxt : adj[1])
		pq.push({ nxt.first, 1, nxt.second });

	while (cnt < v - 1)
	{
		int cost, a, b;
		tie(cost, a, b) = pq.top();
		pq.pop();

		if (check[b])
			continue;
		ans += cost;
		check[b] = 1;
		cnt++;
		for (auto nxt : adj[b])
		{
			if (!check[nxt.second])
				pq.push({ nxt.first, b, nxt.second });
		}
	}
	cout << ans;
}

 

 

3. 더 풀어보기


https://www.acmicpc.net/problem/1368

 

https://www.acmicpc.net/problem/1647

 

 

 

 

 

 

'알고리즘(코딩테스트)' 카테고리의 다른 글

문자열 관련  (0) 2025.05.20
알고리즘 수업 최종 정리  (0) 2025.04.28
LCS  (0) 2025.04.23
DP (배낭 문제)  (0) 2025.04.11
백트래킹 2  (0) 2025.04.04
'알고리즘(코딩테스트)' 카테고리의 다른 글
  • 문자열 관련
  • 알고리즘 수업 최종 정리
  • LCS
  • DP (배낭 문제)
gbleem
gbleem
gbleem 님의 블로그 입니다.
  • gbleem
    gbleem 님의 블로그
    gbleem
  • 전체
    오늘
    어제
    • 분류 전체보기 (184)
      • Unreal Engine (73)
      • C++ (19)
      • 알고리즘(코딩테스트) (27)
      • TIL (60)
      • CS (4)
      • 툴 (1)
  • 블로그 메뉴

    • 홈
    • 카테고리
  • 링크

    • 과제용 깃허브
    • 깃허브
    • velog
  • 공지사항

  • 인기 글

  • 태그

    map을 vector로 복사
    DP
    cin함수
    character animation
    C++
    addonscreendebugmessage
    additive animation
    const
    blend pose
    gamestate
    BFS
    상속
    motion matching
    applydamage
    싱글턴
    actor 클래스
    매크로 지정자
    Vector
    enhanced input system
    템플릿
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
gbleem
MST
상단으로

티스토리툴바