티스토리 뷰

반응형

스패닝 트리 (Spanning Tree) ?

  • 그래프의 정점 전부와 간선의 부분 집합으로 구성된 부분 그래프이다.
  • 아래와 같은 예시들이 스패닝 트리라고 할 수 있다.

  • 스패닝 트리에 포함된 간선들은 정점들을 트리 형태로 전부 연결해야 한다.
  • 또한, 트리 형태여야 한다는 말은 선택된 간선이 사이클을 이루지 않는다는 의미여, 정점들이 부모-자식 관계로 연결될 필요는 없다는 것이다.

 

최소 스패닝 트리 (MST, Minimum Spanning Tree) ?

  • 가중치 그래프의 스패닝 트리 중 가중치의 합이 가장 작은 트리이다.
  • 최소 스패닝 트리를 구할 수 있는 알고리즘은 두 가지가 있다.

 

프림 (Prim) 알고리즘

  • 크루스칼과 달리 프림 하나의 시작점으로 구성된 트리에 간선을 하나씩 추가하며 스패닝 트리가 될 때까지 키워 간다.
  • 따라서 항상 선택된 간선들은 중간 과정에서도 항상 연결된 트리를 이루게 된다.
  • 이미 만들어진 트리에 인접한 간선만을 고려한다는 점을 제외하면 크루스칼과 동일하다.
  • 우선순위 큐를 사용하면 시간 복잡도 O(E * log V) 를 갖는다.
  • 프림 알고리즘은 노드의 수에 영향을 받기 때문에, 노드의 수가 적고 간선의 수가 많은 그래프에서 효율적이다.

과정

  • 스패닝 트리에 포함된 정점은 파란색 원으로, 포함된 간선은 빨간색 굵은 실선으로 나타냈다.
  • 이때 그림에서 회색 점선으로 표시된 간선들은 다음 단계에 트리에 추가될 가능성이 있는 후보 간선들로, 트리에 속한 정점 하나와 트리에 속하지 않은 정점 하나를 연결한다.
  • Roop 3에서 간선 (B, D) 는 이미 트리에 속한 정점들을 연결하기 때문에 후보 간선이 아니다.

 

Code

그래프를 형성하는 Graph 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Graph {
    List<Edge>[] edge;
 
    public Graph(int V) {
        edge = new LinkedList[V + 1];
 
        for (int i = 1; i <= V; i++)
            edge[i] = new LinkedList<>();
    }
 
    // 양방향 그래프
    public void AddEdge(int x, int y, int cost) {
        edge[x].add(new Edge(x, y, cost));
        edge[y].add(new Edge(y, x, cost));
    }
}

 

간선의 정보를 담는 Edge 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Edge implements Comparable<Edge> {
    int x, y, cost;
 
    public Edge(int x, int y, int cost) {
        this.x = x;
        this.y = y;
        this.cost = cost;
    }
 
    @Override // 우선순위 큐를 사용하기 위한 함수 오버라이딩
    public int compareTo(Edge e) {
        return this.cost - e.cost;
    }
}

 

Prim 알고리즘을 수행하는 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void Prim() {
    PriorityQueue<Edge> pq = new PriorityQueue<>(); // 가중치가 낮은 순대로 간선을 정렬할 우선순위
    Queue<Integer> queue = new LinkedList<>();      // 정점방문 스케줄 처리를 위한 큐
 
    queue.add(1);                                   // 정점 1을 시작정점으로 선택
 
    while (!queue.isEmpty()) {
        int from = queue.poll();
        visited[from] = true;
 
        for (Edge edge : graph.edge[from]) {        // 현재 정점 from과 연결된 간선 중
            if (!visited[edge.to]) {                // 아직 정점 to를 방문하지 않았다면
                pq.add(edge);                       // 우선순위 큐에 간선을 추가한다.
            }
        }
 
        while (!pq.isEmpty()) {
            Edge edge = pq.poll();                  // 우선순위 큐에 의해 가중치가 가장 작은 간선이 나올 것이며,
            if (!visited[edge.to]) {                // 간선이 연결된 정점 to를 방문한 적이 없다면,
                queue.add(edge.to);                 // 큐에 삽입하여 다음에 방문한다.
                visited[edge.to] = true;            // 방문했던 정점을 다시 방문하지 않도록 방문표시.
                mst.add(edge);                      // 최소 스패닝 트리를 구성하는 간선 추가.
                min += edge.cost;                   // 총 최소 가중치 합을 구하기 위해 덧셈.
                break;
            }
        }
    }
}

 

전체 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import java.util.*;
 
public class test1 {
    static int V, E, min = 0;
    static Graph graph;
    static boolean[] visited;
    static ArrayList<Edge> mst;
 
    public static void main(String[] args) {
        V = 9;
        E = 14;
        visited = new boolean[V + 1];
        mst = new ArrayList<>();
        graph = new Graph(V);
 
        graph.AddEdge(124);
        graph.AddEdge(238);
        graph.AddEdge(347);
        graph.AddEdge(459);
        graph.AddEdge(5610);
        graph.AddEdge(672);
        graph.AddEdge(781);
        graph.AddEdge(897);
        graph.AddEdge(188);
        graph.AddEdge(2811);
        graph.AddEdge(364);
        graph.AddEdge(392);
        graph.AddEdge(4614);
        graph.AddEdge(796);
 
        Prim();
 
        for (Edge edge : mst)
            System.out.println(edge.from + " - " + edge.to + " cost : " + edge.cost);
 
        System.out.println(min);
    }
 
    public static void Prim() {
        PriorityQueue<Edge> pq = new PriorityQueue<>(); // 가중치가 낮은 순대로 간선을 정렬할 우선순위
        Queue<Integer> queue = new LinkedList<>();      // 정점방문 스케줄 처리를 위한 큐
 
        queue.add(1);                                   // 정점 1을 시작정점으로 선택
 
        while (!queue.isEmpty()) {
            int from = queue.poll();
            visited[from] = true;
 
            for (Edge edge : graph.edge[from]) {        // 현재 정점 from과 연결된 간선 중
                if (!visited[edge.to]) {                // 아직 정점 to를 방문하지 않았다면
                    pq.add(edge);                       // 우선순위 큐에 간선을 추가한다.
                }
            }
 
            while (!pq.isEmpty()) {
                Edge edge = pq.poll();                  // 가중치가 가장 적은 간선이 나올 것이며,
                if (!visited[edge.to]) {                // 간선이 연결된 정점 to를 방문한 적이 없다면,
                    queue.add(edge.to);                 // 큐에 삽입하여 다음에 방문한다.
                    visited[edge.to] = true;            // 방문했던 정점을 다시 방문하지 않도록 방문표시.
                    mst.add(edge);                      // 최소 스패닝 트리를 구성하는 간선 추가.
                    min += edge.cost;                   // 총 최소 가중치 합을 구하기 위해 덧셈.
                    break;
                }
            }
        }
    }
}
 
class Graph {
    List<Edge>[] edge;
 
    public Graph(int V) {
        edge = new LinkedList[V + 1];
 
        for (int i = 1; i <= V; i++)
            edge[i] = new LinkedList<>();
    }
 
    // 양방향 그래프
    public void AddEdge(int from, int to, int cost) {
        edge[from].add(new Edge(from, to, cost));
        edge[to].add(new Edge(to, from, cost));
    }
}
 
class Edge implements Comparable<Edge> {
    int from, to, cost;
 
    public Edge(int from, int to, int cost) {
        this.from = from;
        this.to = to;
        this.cost = cost;
    }
 
    @Override // 우선순위 큐를 사용하기 위한 함수 오버라이딩
    public int compareTo(Edge e) {
        return this.cost - e.cost;
    }
}
반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함