ShovelingLife
A Game Programmer
ShovelingLife
전체 방문자
오늘
어제
  • 분류 전체보기 (1072)
    • 그래픽스 (57)
      • 공통 (19)
      • 수학 물리 (22)
      • OpenGL & Vulkan (1)
      • DirectX (14)
    • 게임엔진 (183)
      • Unreal (69)
      • Unity (103)
      • Cocos2D-X (3)
      • 개인 플젝 (8)
    • 코딩테스트 (221)
      • 공통 (7)
      • 프로그래머스 (22)
      • 백준 (162)
      • LeetCode (19)
      • HackerRank (2)
      • 코딩테스트 알고리즘 (8)
    • CS (235)
      • 공통 (21)
      • 네트워크 (44)
      • OS & 하드웨어 (55)
      • 자료구조 & 알고리즘 (98)
      • 디자인패턴 (6)
      • UML (4)
      • 데이터베이스 (7)
    • 프로그래밍 언어 (348)
      • C++ (167)
      • C# (90)
      • Java (9)
      • Python (33)
      • SQL (30)
      • JavaScript (8)
      • React (7)
    • 그 외 (9)
      • Math (5)
      • 일상 (5)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • Source Code 좌측 상단에 복사 버튼 추가 완료
  • 언리얼 엔진 C++ 빌드시간 단축 꿀팁
  • 게임 업계 코딩테스트 관련
  • 1인칭 시점으로 써내려가는 글들

인기 글

태그

  • 언리얼
  • 함수
  • 유니티
  • C++
  • 오블완
  • C
  • c#
  • 백준
  • 문자열
  • string
  • 배열
  • 알고리즘
  • 클래스
  • 파이썬
  • Unity
  • 포인터
  • SQL
  • 프로그래머스
  • 그래픽스
  • 티스토리챌린지

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
ShovelingLife

A Game Programmer

C++ 프림(Prim) 알고리즘으로 MST 찾기
CS/자료구조 & 알고리즘

C++ 프림(Prim) 알고리즘으로 MST 찾기

2023. 8. 12. 19:57

1. 프림(Prim) 알고리즘이란?

최소신장트리(MST, Minimum Spanning Tree) 를 찾기 위한 대표적인 알고리즘이다.

여기에서 최소신장트리란, 아래와 같이 모든 노드를 연결하는 부분 그래프 중, 가장 비용이 적은 것이다.

 

하늘색으로 표시한 경로가 최소신장트리이다.

여기에서 최소신장트리의 길이는 (4 + 8 + 16 + 20) = 48다.

 

최소신장트리를 찾는 알고리즘은 크루스칼(Kruskal) 과 프림(Prim) 이 대표적이다.

2. 동작원리

프림 알고리즘에서는 MST의 후보가 될 간선을 담을 우선순위 큐가 필요하다.

우선순위 큐는 최소의 비용을 가지는 경로가 우선순위를 갖게 한다.

(보통 Min Heap을 이용해서 구현한다.)

 

가장 먼저, 그래프에서 아무 노드나 선택하므로 가장 번호가 빠른 노드를 선택한다. 그리고, 선택된 노드에 연결된 모든 간선을 우선순위 큐에 넣는다.

 

그리고 이 중에서, 우선순위 큐에서 값을 하나 뺀다.

여기에서는 가장 위에 있는 가중치 4짜리 간선이 선택될 것이다.

이제 이 간선을 MST의 포함되는 간선으로 삼으며 아래와 같다.

 

이제 정점 1과 정점 2를 잇는 간선을 선택했으므로, 정점 2에 대해서 연결된 간선을 모두 우선순위 큐에 추가한다.

 

 

그리고 똑같이, 우선순위 큐에서 간선을 하나 빼서 MST 후보로 추가한다.

 

다음 차례는 위의 과정을 반복하므로 아래와 같은 상태가 된다.

 

하지만 아래에서처럼, 우선순위 큐에 있는 가중치 9 짜리의 간선을 선택하면 루프가 생기게 되므로 MST의 후보라고 생각하지 않는다. (빨간색으로 표시한 선)

 

그리고 다음 우선순위 큐의 원소를 추출하여 과정을 반복한다.

 

정점 3과 정점 4를 잇는 간선은 MST를 만들지 않으므로 이 간선 역시 MST의 후보가 되었다.

 

정점의 개수가 N 개일 때, 이렇게 우선순위 큐에서 뺀 간선을 MST 후보로 추가하는 과정을 간선이 N-1 개 만들어질 때까지 반복하면 MST가 만들어진다.

#include <iostream>

#define MAX_NODE	50000
#define MAX_EDGE	200000

using namespace std;

typedef struct Edge {
	int from;
	int to;
	int weight;
	Edge* next;
	Edge() { from = 0, to = 0, weight = 0, next = NULL; }
	Edge(int newFrom, int newTo, int newWeight) { from = newFrom, to = newTo, weight = newWeight, next = NULL; }
} Edge;

typedef struct List {
	Edge* head;
	List() { head = NULL; }
} List;

typedef struct Heap{
	Edge heap[MAX_EDGE];
	int heapSize;

	Heap() { heapSize = 0; }
} Heap;

// Variables
Heap h;
List* list[MAX_NODE];
int N, M;
bool included[MAX_NODE];

void listAdd(List* list, int from, int to, int weight)
{
	Edge* edge = new Edge(from, to, weight);
	Edge* head = list->head;

	if (list->head == NULL)
		list->head = edge;
	else 
	{
		while (head->next != NULL) head = head->next;
		head->next = edge;
	}
}

void heapInit(Heap* h) { h->heapSize = 0; }
void heapPush(Heap* h, Edge edge)
{
	int idx = ++(h->heapSize);

	while (idx != 1 && (h->heap[idx / 2].weight > edge.weight))
	{
		h->heap[idx] = h->heap[idx / 2];
		idx /= 2;
	}
	h->heap[idx] = edge;
}
Edge heapPop(Heap* h)
{
	Edge edge = h->heap[1];
	Edge temp = h->heap[(h->heapSize)--];
	int parent = 1;
	int child = 2;

	while (child <= h->heapSize)
	{
		if (child < h->heapSize && h->heap[child].weight > h->heap[child + 1].weight)
			child++;
		if (temp.weight <= h->heap[child].weight) break;

		h->heap[parent] = h->heap[child];
		parent = child;
		child *= 2;
	}
	h->heap[parent] = temp;
	return edge;
}

int prim()
{
	int answer = 0;

	for (int i = 0; i < MAX_NODE; i++) included[i] = false;
	included[0] = true;

	Edge edge;
	heapInit(&h);

	Edge* head = list[0]->head;
	while (head != NULL) {
		heapPush(&h, *head);
		head = head->next;
	}
	int numCheck = 0;
	while(numCheck != N - 1) {
		// Choose next edge
		edge = heapPop(&h);

		if (!included[edge.to])
		{
			answer += edge.weight;
			included[edge.to] = true;

			head = list[edge.to]->head;
			while (head != NULL) {
				if(!included[head->to])
					heapPush(&h, *head);
				head = head->next;
			}
			numCheck++;
		}
	}
	return answer;
}

int main(void)
{
	cin.tie(NULL);
	ios::sync_with_stdio(false);

	int answer = 0;

	cin >> N;

	for (int i = 0; i < N; i++)
		list[i] = new List();

	cin >> M;
	for (int i = 0; i < M; i++)
	{
		int from, to, weight;
		cin >> from >> to >> weight;
		listAdd(list[from - 1], from - 1, to - 1, weight);
		listAdd(list[to - 1], to - 1, from - 1, weight);
	}
	cout << prim() << '\n';

	for (int i = 0; i < N; i++) 
	{
		Edge* head = list[i]->head;
		while (head != NULL){
			Edge* tmp = head;
			head = head->next;
			delete tmp;
		}
		delete[] list[i];
	}
	return 0;
}

[알고리즘] 프림(Prim) 알고리즘으로 MST 찾기 (C++로 구현하기) (tistory.com)

저작자표시 (새창열림)

'CS > 자료구조 & 알고리즘' 카테고리의 다른 글

[C#] 힙 (Heap)  (0) 2023.08.29
비헤이비어 트리 (Behavior Tree)  (0) 2023.08.17
[C++] STL 연관 컨테이너(associative container), set, multiset  (0) 2023.08.11
[C++] STL 연관 컨테이너(associative container), map, multimap  (0) 2023.08.11
[C++] STL list(리스트), 시퀀스 컨테이너  (0) 2023.08.11
    'CS/자료구조 & 알고리즘' 카테고리의 다른 글
    • [C#] 힙 (Heap)
    • 비헤이비어 트리 (Behavior Tree)
    • [C++] STL 연관 컨테이너(associative container), set, multiset
    • [C++] STL 연관 컨테이너(associative container), map, multimap
    ShovelingLife
    ShovelingLife
    Main skill stack => Unity C# / Unreal C++ Studying Front / BackEnd, Java Python

    티스토리툴바