프림 알고리즘

2024. 10. 24. 17:12Algorithms

프림 알고리즘 (Prim's Algorithm) 이해하기

프림 알고리즘(Prim's Algorithm)최소 신장 트리(MST, Minimum Spanning Tree)를 찾기 위한 대표적인 그리디 알고리즘입니다. 주어진 가중치 그래프에서 모든 노드를 최소한의 비용으로 연결하는 트리를 구하는 데 사용되며, 크루스칼 알고리즘(Kruskal's Algorithm)과 함께 널리 사용되는 알고리즘 중 하나입니다.

이 포스팅에서는 프림 알고리즘의 기본 개념, 동작 방식, 구현 방법, 그리고 실제 사례를 통해 이를 자세히 알아보겠습니다.


1. 최소 신장 트리(MST)란?

최소 신장 트리(MST)는 주어진 연결 그래프(Connected Graph)에서 모든 노드를 연결하는 트리 중 가중치 합이 최소인 트리를 말합니다.

  • 신장 트리(Spanning Tree): 주어진 그래프의 모든 노드를 포함하는 트리 구조입니다. 트리는 사이클이 없어야 하고, 간선은 N개의 노드를 연결하는 최소한의 개수(N-1)여야 합니다.
  • 최소 신장 트리: 여러 신장 트리 중, 간선들의 가중치 합이 가장 작은 트리입니다.

프림 알고리즘은 네트워크 구축이나 케이블 배선 등, 비용을 최소화하면서 모든 노드를 연결해야 하는 상황에서 유용합니다.


2. 프림 알고리즘의 기본 원리

프림 알고리즘은 그리디(Greedy)한 방식으로 동작하여, 점진적으로 최소 비용의 간선을 선택하면서 그래프를 확장합니다. 알고리즘은 임의의 시작 노드에서 시작하여, 연결된 노드들을 확장해가면서 트리를 완성합니다.

2.1. 동작 방식

  1. 시작 노드를 선택하고, 해당 노드를 트리에 추가합니다.
  2. 현재 트리에 포함된 노드들과 연결된 가장 작은 가중치의 간선을 선택하여 트리에 추가합니다.
  3. 트리에 포함된 노드가 모든 노드를 포함할 때까지 2단계를 반복합니다.
  4. 사이클이 없으면서도 모든 노드를 연결하는 최소 신장 트리가 완성됩니다.

3. 프림 알고리즘의 동작 과정 (예시)

아래와 같은 그래프에서 프림 알고리즘을 통해 최소 신장 트리를 구하는 예시를 살펴보겠습니다.

A -- 1 -- B
|        /  |
4       2   3
|   /       |
C -- 5 -- D
  1. 노드 A를 시작 노드로 선택합니다. A와 연결된 간선 중 가중치가 가장 작은 1을 선택하여 노드 B를 추가합니다.
  2. 트리에는 현재 A와 B가 포함되어 있습니다. 이제 트리에서 연결할 수 있는 간선 중 가중치가 작은 2를 선택하여 노드 D를 추가합니다.
  3. 트리에는 A, B, D가 포함되어 있습니다. 연결할 수 있는 간선 중 가중치가 작은 3을 선택하여 노드 C를 추가합니다.
  4. 이제 모든 노드가 트리에 포함되었으므로 알고리즘이 종료됩니다.

결과적으로, 최소 신장 트리는 A - B - D - C로 구성되며, 가중치의 총합은 1 + 2 + 3 = 6입니다.


4. 프림 알고리즘의 구현 (C# 예시)

프림 알고리즘을 C#으로 구현한 예시는 다음과 같습니다.

using System;
using System.Collections.Generic;

public class PrimAlgorithm
{
    public static void FindMST(Dictionary<string, Dictionary<string, int>> graph, string startNode)
    {
        var mstSet = new HashSet<string>(); // 트리에 포함된 노드 집합
        var edgeQueue = new SortedSet<(int weight, string from, string to)>();
        var mstEdges = new List<(string from, string to, int weight)>();

        // 시작 노드를 트리에 추가
        mstSet.Add(startNode);

        // 시작 노드와 연결된 간선들을 큐에 추가
        foreach (var (neighbor, weight) in graph[startNode])
        {
            edgeQueue.Add((weight, startNode, neighbor));
        }

        while (mstSet.Count < graph.Count)
        {
            var (weight, from, to) = edgeQueue.Min;
            edgeQueue.Remove(edgeQueue.Min);

            if (mstSet.Contains(to)) continue;

            mstSet.Add(to); // 새로운 노드를 트리에 추가
            mstEdges.Add((from, to, weight));

            foreach (var (neighbor, w) in graph[to])
            {
                if (!mstSet.Contains(neighbor))
                {
                    edgeQueue.Add((w, to, neighbor));
                }
            }
        }

        // 최소 신장 트리 출력
        foreach (var (from, to, weight) in mstEdges)
        {
            Console.WriteLine($"{from} - {to} : {weight}");
        }
    }

    public static void Main()
    {
        var graph = new Dictionary<string, Dictionary<string, int>>
        {
            { "A", new Dictionary<string, int> { { "B", 1 }, { "C", 4 } } },
            { "B", new Dictionary<string, int> { { "A", 1 }, { "C", 2 }, { "D", 3 } } },
            { "C", new Dictionary<string, int> { { "A", 4 }, { "B", 2 }, { "D", 5 } } },
            { "D", new Dictionary<string, int> { { "B", 3 }, { "C", 5 } } }
        };

        FindMST(graph, "A");
    }
}

4.1. 코드 설명

  • Graph: 인접 리스트를 사용하여 그래프를 표현합니다. 노드 간의 연결 정보와 간선의 가중치가 포함됩니다.
  • PrimAlgorithm 클래스: 프림 알고리즘을 구현한 클래스입니다. FindMST 메서드는 그래프에서 최소 신장 트리를 찾고, 트리에 포함된 간선과 가중치를 출력합니다.
  • SortedSet: 우선순위 큐로 사용되며, 가중치가 작은 간선부터 선택하도록 합니다.

5. 프림 알고리즘의 사용 사례

5.1. 네트워크 설계

  • 프림 알고리즘은 네트워크 케이블 연결 비용을 최소화하는 데 유용합니다. 예를 들어, 도시 간 통신 네트워크나 컴퓨터 네트워크에서 최소한의 케이블로 모든 장치를 연결하는 최적의 방법을 찾는 데 사용됩니다.

5.2. 전력망 설계

  • 전력선을 효율적으로 배치하기 위해 최소 신장 트리를 사용하는 경우가 많습니다. 여러 지역을 전력망으로 연결할 때, 최소한의 비용으로 모든 지역에 전력을 공급하기 위한 최적의 경로를 찾아내는 데 적용됩니다.

5.3. 도로 건설

  • 여러 도시를 연결하는 도로 건설에서도 프림 알고리즘이 사용됩니다. 모든 도시를 연결하면서 도로 건설 비용을 최소화하는 경로를 찾는 것이 목적입니다.

6. 프림 알고리즘의 성능

프림 알고리즘의 성능은 사용된 우선순위 큐에 따라 달라집니다.

  • 이진 힙(Binary Heap)을 사용하면 시간 복잡도는 O(E log V)가 됩니다. 여기서 E는 그래프의 간선 수, V는 노드 수입니다.
  • 일반적인 경우, 프림 알고리즘은 조밀한 그래프(dense graph)에 더 적합하며, 간선의 개수가 많은 경우 크루스칼 알고리즘보다 성능이 더 좋습니다.

7. 프림 알고리즘의 한계와 비교

프림 알고리즘은 간선의 가중치가 모두 비음수일 때 사용되며, 연결 그래프에서만 최적의 해를 보장합니다. 프림 알고리즘과 자주 비교되는 알고리즘으로 크루스칼 알고리즘(Kruskal's Algorithm)이 있습니다.

  • 프림 알고리즘은 트리를 확장하는 방식이며, 시작점에 따라 탐색이 다를 수 있습니다.
  • 크루스칼 알고리즘은 간선을 정렬한 후 작은 가중치부터 추가하는 방식으로, 그래프의 노드 연결 상태에 독립적입니다.

프림 알고리즘은 밀집 그래프에, 크루스칼 알고리즘은 희소 그래프에 적합합니다.


프림 알고리즘은 주어진 가중치 그래프에서 최소한의 비용으로 모든 노드를 연결하는 최소 신장 트리를 찾는 강력한 도구입니다. 네트워크 설계, 전력망 설계, 도로 건설 등 다양한 실제 문제에서 효과적으로 사용됩니다. 그리디 방식을 사용하여 점진적으로 최적의 해를 구하는 프림 알고리즘을 이해하면, 그래프 이론최적화 문제 해결에 큰 도움이 될 것입니다.

'Algorithms' 카테고리의 다른 글

탐욕 알고리즘  (1) 2024.10.27
크루스칼 알고리즘  (0) 2024.10.24
다익스트라 길찾기 알고리즘  (0) 2024.10.24
A-Star 길찾기 알고리즘  (5) 2024.10.24
그래프 알고리즘  (1) 2024.10.24