5 ๋ถ„ ์†Œ์š”

MST(์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ)์— ๋Œ€ํ•ด์„œโ€ฆ

MST๋ž€ โ€˜์ตœ์†Œ์‹ ์žฅํŠธ๋ฆฌโ€™๋กœ, ๊ฐ€์žฅ ๋น„์šฉ์ด ์ ์€ ๊ฒฝ๋กœ๋กœ ์ด๋ฃจ์–ด์ง„ ํŠธ๋ฆฌ๋ฅผ ๋งํ•œ๋‹ค.
MST๋ฅผ ์•Œ๊ธฐ ์ „์— Spanning Tree์ฆ‰, ์‹ ์žฅํŠธ๋ฆฌ๋ถ€ํ„ฐ ๋จผ์ € ์•Œ์•„์•ผ ํ•œ๋‹ค.


1. Spanning Tree (์‹ ์žฅํŠธ๋ฆฌ)

Spanning Tree๋ž€ ๊ทธ๋ž˜ํ”„ ๋‚ด์˜ ๋ชจ๋“  vertex๋ฅผ ํฌํ•จํ•˜๋Š” ํŠธ๋ฆฌ์ด๋‹ค.

  • Spanning Tree๋Š” ๊ทธ๋ž˜ํ”„์˜ โ€˜์ตœ์†Œ ์—ฐ๊ฒฐ ๋ถ€๋ถ„ ๊ทธ๋ž˜ํ”„โ€™์ด๋‹ค. (์ฆ‰, ๊ทธ๋ž˜ํ”„์—์„œ ์ผ๋ถ€ edge๋ฅผ ์„ ํƒํ•ด์„œ ๋งŒ๋“  ํŠธ๋ฆฌ์ด๋‹ค)
    • ์ตœ์†Œ ์—ฐ๊ฒฐ = edge์˜ ์ˆ˜๊ฐ€ ๊ฐ€์žฅ ์ ์Œ.
    • n๊ฐœ์˜ vertex๋ฅผ ๊ฐ–๋Š” ๊ทธ๋ž˜ํ”„์˜ ์ตœ์†Œ edge์˜ ์ˆ˜๋Š” n-1๊ฐœ์ด๋‹ค.
    • n-1๊ฐœ์˜ edge๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฉด ๋ฐ˜๋“œ์‹œ ํŠธ๋ฆฌํ˜•ํƒœ๊ฐ€ ๋˜๊ณ , ์ด ๊ฒƒ์„ ์‹ ์žฅํŠธ๋ฆฌ๋ผ๊ณ  ํ•œ๋‹ค.

1-1. Spanning Tree์˜ ํŠน์ง•

  • DFS(๊นŠ์ด์šฐ์„ ํƒ์ƒ‰), BFS(๋„ˆ๋น„์šฐ์„ ํƒ์ƒ‰)์„ ์ด์šฉํ•˜์—ฌ ๊ทธ๋ž˜ํ”„์—์„œ ์‹ ์žฅํŠธ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.
  • ํ•˜๋‚˜์˜ ๊ทธ๋ž˜ํ”„์—๋Š” ๋‹ค์–‘ํ•œ ์‹ ์žฅํŠธ๋ฆฌ๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ๊ณ , ๊ทธ ์ค‘ ๊ฐ€์žฅ ์ ์€ ๋น„์šฉ์˜ ์‹ ์žฅํŠธ๋ฆฌ๋ฅผ MST(์ตœ์†Œ์‹ ์žฅํŠธ๋ฆฌ)๋ผ๊ณ  ํ•œ๋‹ค.
  • ์‹ ์žฅํŠธ๋ฆฌ๋Š” ํŠน์ˆ˜ํ•œ ํ˜•ํƒœ์˜ ํŠธ๋ฆฌ์ด๋ฏ€๋กœ, ๋ชจ๋“  vertex๋“ค์ด connected๋˜์–ด ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, cycle์„ ํ˜•์„ฑํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.
  • n๊ฐœ์˜ vertex๋ฅผ ์ •ํ™•ํžˆ n-1๊ฐœ์˜ ๊ฐ„์„ ์œผ๋กœ ์—ฐ๊ฒฐํ•œ๋‹ค.

2. MST (์ตœ์†Œ์‹ ์žฅํŠธ๋ฆฌ)

Spanning Tree ์ค‘์—์„œ ์‚ฌ์šฉ๋œ edge์˜ weight(๊ฐ€์ค‘์น˜)์˜ ํ•ฉ์ด ๊ฐ€์žฅ ์ž‘์€ ํŠธ๋ฆฌ์ด๋‹ค.

  • ๊ทธ๋ž˜ํ”„์— ์žˆ๋Š” ๋ชจ๋“  vertex๋“ค์„ ๊ฐ€์žฅ ์ ์€ ๋น„์šฉ์˜ edge๋“ค๋กœ ์—ฐ๊ฒฐํ•จ

[์˜ˆ์‹œ] image

2-1. MST์˜ ํŠน์ง•

  • edge์˜ ๊ฐ€์ค‘์น˜์˜ ํ•ฉ์ด ์ตœ์†Œ์—ฌ์•ผ ํ•œ๋‹ค.
  • n๊ฐœ์˜ vertex๋ฅผ ๊ฐ€์ง€๋Š” ๊ทธ๋ž˜ํ”„์— ๋Œ€ํ•ด ๋ฐ˜๋“œ์‹œ n-1๊ฐœ์˜ ๊ฐ„์„ ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.
  • cycle์ด ์žˆ์–ด์„  ์•ˆ๋œ๋‹ค.
  • ๊ทธ๋ž˜ํ”„ G์˜ MST T๋ฅผ ์ฐพ์•˜๋‹ค๊ณ  ํ•ด์„œ, ๊ทธ ํŠธ๋ฆฌ๊ฐ€ ์œ ์ผํ•œ MST๊ฐ€ ์•„๋‹ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ๋‹ค๋ฅธ MST Tโ€™์ด ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ค.

2-2. MST์˜ ํ™•์žฅ

T : G์˜ MST, A๋Š” T์˜ subtree๋ผ๊ณ  ํ•˜์ž.  
A์™€ V-A๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” edge(u,v)๋ฅผ `light edge`๋ผ๊ณ  ํ–ˆ์„ ๋•Œ, edge(u,v)๋Š” MST-T์— ์ข…์†๋œ๋‹ค.  

[๊ณผ์ •]
edge(u,v)๊ฐ€ ๋น„์šฉ์ด ๊ฐ€์žฅ ์ ์€ edge์ด๋ฉด, V-A์—์„œ ๋…ธ๋“œ(v)๋ฅผ A๋กœ ๊ฐ€์ ธ์˜จ๋‹ค. ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜๋ฉด MST๋ฅผ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

safe edge๋ž€ โ€œ๋น„์šฉ(cost)๊ฐ€ ๊ฐ€์žฅ ์ €๋ ดํ•˜๋ฉด์„œ cycle์„ ํ˜•์„ฑํ•˜์ง€ ์•Š๋Š” edgeโ€๋ฅผ ๋งํ•œ๋‹ค.

  • S : vertex ์ „์ฒด์˜ ์ง‘ํ•ฉ
  • V : ์ „์ฒด ๊ทธ๋ž˜ํ”„ ์ง‘ํ•ฉ
  • A : ์ „์ฒด edge ์ง‘ํ•ฉ
  • Cut : ๊ทธ๋ž˜ํ”„๋ฅผ Partition์œผ๋กœ ๋‚˜๋ˆ„๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.
    • ์˜ˆ) S์™€ V-S์˜ ํŒŒํ‹ฐ์…˜์œผ๋กœ ๋ถ„๋ฆฌ
  • Cross : edge(u,v)์—์„œ u์™€ v๋Š” ๊ฐ๊ฐ ๋‹ค๋ฅธ ํŒŒํ‹ฐ์…˜์— ์กด์žฌํ•˜๊ณ , ์ด๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” edge๋ฅผ cross๋ผ๊ณ  ํ•œ๋‹ค.
  • Respect : ์–ด๋–ค edge-set์—์„œ cut์„ ๊ฑด๋„ˆ๊ฐ€์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
  • Light edge : cross-edge ์ค‘ ๊ฐ€์žฅ ์ž‘์€ edge์ด๋‹ค.

image

2-3. MST ๊ตฌํ˜„ ์•Œ๊ณ ๋ฆฌ์ฆ˜

2-3-1. Generic-MST ์˜์‚ฌ์ฝ”๋“œ

image

2-3-2. Kruskal Algorithm (ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜)

Kruskal Algorithm์ด๋ž€ greedy algorithm(ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜)์„ ์ด์šฉํ•˜์—ฌ ๊ทธ๋ž˜ํ”„์˜ ๋ชจ๋“  vertex๋ฅผ ์ตœ์†Œ ๋น„์šฉ์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.
์ฆ‰, ๋น„์šฉ์ด ๊ฐ€์žฅ ์‹ผ edge๋ฅผ ์„ ํƒํ•ด ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด ๋‚˜๊ฐ€๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

  • greedy algorithm : ๋ฏธ๋ž˜๋ฅผ ์ƒ๊ฐํ•˜์ง€ ์•Š๊ณ  ๊ฐ ๋‹จ๊ณ„์—์„œ ๊ฐ€์žฅ ์ตœ์„ ์˜ ์„ ํƒ์„ ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜ (์ž์‹ ์˜ ์„ ํƒ์ด ์ตœ์„ ์˜ ์„ ํƒ์ด๊ธธ ๋ฐ”๋ผ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜)

[๊ณผ์ •]

  1. ๊ทธ๋ž˜ํ”„์˜ edge๋“ค์„ weight์˜ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•œ๋‹ค.
  2. ์ •๋ ฌ๋œ edge๋ฆฌ์ŠคํŠธ์—์„œ ์ˆœ์„œ๋Œ€๋กœ cycle์„ ํ˜•์„ฑํ•˜์ง€ ์•Š๋Š” edge๋ฅผ ์„ ํƒํ•œ๋‹ค.
    • ๊ฐ€์žฅ ๋‚ฎ์€ ๊ฐ€์ค‘์น˜๋ฅผ ๋จผ์ € ์„ ํƒ
    • cycle์„ ๋งŒ๋“œ๋Š” edge๋Š” ์ œ์™ธ
  3. ํ•ด๋‹น edge๋ฅผ ํ˜„์žฌ์˜ MST์˜ ์ง‘ํ•ฉ์— ์ถ”๊ฐ€ํ•œ๋‹ค.

[์˜์‚ฌ์ฝ”๋“œ]
image

[์˜ˆ์ œ์ฝ”๋“œ] ์ฝ”๋“œ๋Š” ๋‹ค์‹œ ๋‚ด๊ฐ€ ์งœ๋ณผ๊ฒ๋‹ˆ๋‹ค..

from collections import deque
 
 
def mst():
    def upward(buf, idx):
        parent = mst_nodes[idx]
        if parent < 0:
            return idx
        buf.append(idx)
        return upward(buf, parent)
 
    def find(idx):
        buf = []
        result = upward(buf, idx)
        for i in buf:
            mst_nodes[i] = result
        return result
 
    def union(x, y):
        x, y = find(x), find(y)
        if x == y:
            return False
        if mst_nodes[x] < mst_nodes[y]:
            mst_nodes[y] = x
        elif mst_nodes[x] > mst_nodes[y]:
            mst_nodes[x] = y
        else:
            mst_nodes[x] -= 1
            mst_nodes[y] = x
        return True
 
    V, E = 6, 9
    edges = [[1, 2, 6], [1, 3, 3], [2, 3, 2], [2, 4, 5],
             [3, 4, 3], [3, 5, 4], [4, 5, 2], [4, 6, 3], [5, 6, 5]]
    edges.sort(key=lambda x: x[2])
    mst_graph = [[0] * V for _ in range(V)]
    mst_nodes = [-1 for _ in range(V)]
    mst = []
    cost = 0
    q = deque(edges)
    while True:
        u, v, w = q.popleft()
        udx, vdx = u - 1, v - 1
        if union(udx, vdx) is False:
            continue
        mst.append((u, v))
        mst_graph[udx][vdx] = 1
        mst_graph[vdx][udx] = 1
        cost += w
        if len(mst) == V - 1:
            break
    print(f'mst cost is {cost}')
    print(mst)
    for row in mst_graph:
        print(*row)
 
 
mst()

import java.util.Arrays;  
import java.util.Scanner;
/*
sample input(์ฒซ ์ค„์˜ ์ฒซ ์ˆซ์ž๋Š” ์ •์ ์˜ ๊ฐœ์ˆ˜, ๋‘ ๋ฒˆ์งธ ์ˆซ์ž๋Š” ๊ฐ„์„ ์˜ ๊ฐœ์ˆ˜).
6 9
1 6 5
2 4 6
1 2 7
3 5 15
5 6 9
3 4 10
1 3 11
2 3 3
4 5 7
 */
public class Kruskal {
	static int V, E;
	static int[][] graph;
	// ๊ฐ ๋…ธ๋“œ์˜ ๋ถ€๋ชจ
	static int[] parent;
	// ์ตœ์ข…์ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ ์—ฐ๊ฒฐ ๋น„์šฉ.
	static int final_cost;

	public static void main(String[] args) {
		// ๊ทธ๋ž˜ํ”„์˜ ์—ฐ๊ฒฐ์ƒํƒœ(๋…ธ๋“œ1, ๋…ธ๋“œ2, ๋น„์šฉ)๋ฅผ ์ดˆ๊ธฐํ™”.
		Scanner sc = new Scanner(System.in);
		V = sc.nextInt();
		E = sc.nextInt();
		graph = new int[E][3];
		for (int i = 0; i < E; i++) {
			graph[i][0] = sc.nextInt();
			graph[i][1] = sc.nextInt();
			graph[i][2] = sc.nextInt();
		}
		parent = new int[V];
		final_cost = 0;

		// ๊ฐ„์„  ๋น„์šฉ ์ˆœ์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ
		Arrays.sort(graph, (o1, o2) -> Integer.compare(o1[2], o2[2]));

		// makeSet
		for (int i = 0; i < V; i++) {
			parent[i] = i;
		}
		// ๋‚ฎ์€ ๋น„์šฉ๋ถ€ํ„ฐ ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ง„ํ–‰
		for (int i = 0; i < E; i++) {
			// ์‚ฌ์ดํด์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋งŒ ๊ฐ„์„ ์„ ์„ ํƒํ•œ๋‹ค(์—ฌ๊ธฐ์„œ๋Š” ์ตœ์ข… ๋น„์šฉ๋งŒ ๊ณ ๋ คํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค).
			if (find(graph[i][0] - 1) != find(graph[i][1] - 1)) {
				System.out.println("<์„ ํƒ๋œ ๊ฐ„์„ >");
				System.out.println(Arrays.toString(graph[i]));
				union(graph[i][0] - 1, graph[i][1] - 1);
				final_cost += graph[i][2];
				System.out.println("<๊ฐ ๋…ธ๋“œ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ๋ถ€๋ชจ>");
				System.out.println(Arrays.toString(parent) + "\n");
				continue;
			}
		}
		
		System.out.println("์ตœ์ข… ๋น„์šฉ : " + final_cost);
		sc.close();
	}

	private static void union(int a, int b) {
		a = find(a);
		b = find(b);
		if (a > b) {
			parent[a] = b;
		} else {
			parent[b] = a;
		}
	}

	private static int find(int x) {
		if (parent[x] == x)
			return x;
		else
			return find(parent[x]);
	}
}

2-3-3. Prim Algorithm (ํ”„๋ฆผ ์•Œ๊ณ ๋ฆฌ์ฆ˜)

Prim Algorithm์ด๋ž€ ์‹œ์ž‘ ๋…ธ๋“œ์—์„œ ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด๊ฐ€๋ฉฐ ๋‹จ๊ณ„์ ์œผ๋กœ ํŠธ๋ฆฌ๋ฅผ ํ™•์žฅํ•ด๋‚˜๊ฐ€๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

[์˜์‚ฌ์ฝ”๋“œ]
image

[์˜ˆ์ œ์ฝ”๋“œ]

from collections import defaultdict
import heapq
 
def mst():
    V, E = 6, 9
    edges = [[1, 2, 6], [1, 3, 3], [2, 3, 2], [2, 4, 5],
             [3, 4, 3], [3, 5, 4], [4, 5, 2], [4, 6, 3], [5, 6, 5]]
    graph = defaultdict(list)
    for srt, dst, weight in edges:
        graph[srt].append((dst, weight))
        graph[dst].append((srt, weight))
    mst_graph = [[0] * V for _ in range(V)]
    mst_nodes = [-1 for _ in range(V)]
    visited = [True for _ in range(V)]
    q = [(0, 1, 1)]
    while q:
        cost, node, prev = heapq.heappop(q)
        if visited[node - 1] is False:
            continue
        visited[node - 1] = False
        mst_graph[node - 1][prev - 1] = 1
        mst_graph[prev - 1][node - 1] = 1
        mst_nodes[node - 1] = cost
        for dst, weight in graph[node]:
            if visited[dst - 1] is True:
                heapq.heappush(q, (weight, dst, node))
    print(f'MST cost is {sum(mst_nodes)}')
    mst_graph[0][0] = 1
    for row in mst_graph:
        print(*row)
 
mst()

2-3-4. ๋‘ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์‹œ๊ฐ„๋ณต์žก๋„ ๋น„๊ต

Kruskal Algorithm์˜ ์‹œ๊ฐ„๋ณต์žก๋„ : O(eloge)
Prim Algorithm์˜ ์‹œ๊ฐ„๋ณต์žก๋„ : O(n^2)

[๋น„๊ต] ๊ทธ๋ž˜ํ”„์— edge๊ฐ€ ์ ์€ ๊ทธ๋ž˜ํ”„์ธ ํฌ์†Œ๊ทธ๋ž˜ํ”„(Sparse Graph)์ธ ๊ฒฝ์šฐ์—๋Š” Kruskal Aogorithm์ด ์œ ๋ฆฌํ•˜๋‹ค.
๊ทธ๋ž˜ํ”„์— edge๊ฐ€ ๋งŽ์€ ๊ทธ๋ž˜ํ”„์ธ ๋ฐ€์ง‘ ๊ทธ๋ž˜ํ”„(Dense Graph)์ธ ๊ฒฝ์šฐ์—๋Š” Prim Algorithm์ด ์œ ๋ฆฌํ•˜๋‹ค.

ํƒœ๊ทธ:

์นดํ…Œ๊ณ ๋ฆฌ:

์—…๋ฐ์ดํŠธ:

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ