[Python] MST์™€ Kruskal, Prim

songeunmยท2025๋…„ 4์›” 9์ผ
0

Python

๋ชฉ๋ก ๋ณด๊ธฐ
4/6
post-thumbnail

๐ŸŽฑย MST

MST(Minimum Spanning Tree)๋Š” ๊ฐ€์ค‘์น˜๊ฐ€ ์žˆ๋Š” ๋ฌด๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„์—์„œ ์ตœ์†Œ ๋น„์šฉ์œผ๋กœ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ํŠธ๋ฆฌ๋ฅผ ๋งํ•œ๋‹ค. โ€œํŠธ๋ฆฌโ€๋ผ๊ณ  ํ•˜๋Š” ์ด์œ ๋Š” ์ด ๊ทธ๋ž˜ํ”„์— cycle์ด ์—†์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • ๋ชจ๋“  ์ •์  ์—ฐ๊ฒฐ
  • ์‚ฌ์ดํด ์—†์Œ
  • ๊ฐ€์ค‘์น˜์˜ ํ•ฉ์ด ์ตœ์†Œ

MST๋ฅผ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋Œ€ํ‘œ์ ์œผ๋กœ ๋‘๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.
๋ฐ”๋กœ ํฌ๋ฃจ์Šค์นผ(Kruskal) ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ํ”„๋ฆผ(Prim) ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

๋‘˜์˜ ํ๋ฆ„๊ณผ ํ•ต์‹ฌ ๊ฐœ๋…, ๊ทธ๋ฆฌ๊ณ  ๊ตฌํ˜„๊นŒ์ง€ ์•Œ์•„๋ณด์ž!

๐ŸŽฑย Kruskal

ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ฐ„์„ ์„ ์ค‘์‹ฌ์œผ๋กœ ํ•˜๋Š” MST ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

โšฝ๏ธ ํ•ต์‹ฌ ๊ฐœ๋…

๋Œ€๋žต์ ์œผ๋กœ ์‚ดํŽด๋ณด๋Š” ํ๋ฆ„์€ ์ด๋ ‡๋‹ค.

  1. ๋ชจ๋“  ๊ฐ„์„ ์„ ๊ฐ€์ค‘์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•œ๋‹ค. โžก๏ธย O(E log E)
  2. ์ •๋ ฌํ•œ ๊ฐ„์„ ์„ ์ˆœํšŒํ•˜๋ฉฐ ์‚ฌ์ดํด์ด ์ƒ๊ธฐ์ง€ ์•Š์œผ๋ฉด ์„ ํƒํ•œ๋‹ค. โžก๏ธย O(E)
    • ์ด๋•Œ ์‚ฌ์ดํด ์—ฌ๋ถ€๋Š” Union-Find๋ฅผ ํ†ตํ•ด ํ™•์ธํ•œ๋‹ค.

์ •๋ ฌ์ด ์ „์ฒด ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ์ง€๋ฐฐํ•˜๋ฏ€๋กœ ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋Š” O(E log E)๊ฐ€ ๋œ๋‹ค.

โšฝ๏ธ ์ž์„ธํ•œ ํ๋ฆ„

์œ„์˜ ๋‹จ๊ณ„๋“ค์„ ํ•˜๋‚˜ํ•˜๋‚˜ ์‚ดํŽด๋ณด์ž.

์ผ๋‹จ ๊ฐ„์„ ์„ (๊ฐ€์ค‘์น˜, ๋…ธ๋“œA, ๋…ธ๋“œB) ์™€ ๊ฐ™์ด ๋‚˜ํƒ€๋ƒˆ์„ ๋•Œ, ์œ„์™€ ๊ฐ™์ด ์ •๋ ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Step 1

์ฒซ๋ฒˆ์งธ ๊ฐ„์„ ์˜ ๋…ธ๋“œ 1๊ณผ 2๋ฅผ ๊ฐ™์€ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ์–ด์ค€๋‹ค. ์ฆ‰, ์„ ํƒ๋œ(ํŒŒ๋ž€์ƒ‰์œผ๋กœ ์น ํ•ด์ง„) ์ •์ ์ด ์„ ํƒ๋œ ๊ทธ๋ฃน์— ์žˆ๋Š” ์ •์ ์ด ๋œ๋‹ค.
๊ฐ„์„ ์„ ์„ ํƒํ•  ๋•Œ ์ด๋ฏธ ๋‘ ์ •์  ๋ชจ๋‘ ์„ ํƒ๋œ ๊ทธ๋ฃน์— ์†ํ•ด์žˆ๋‹ค๋ฉด ์‚ฌ์ดํด์„ ํ˜•์„ฑํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฑธ๋Ÿฌ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
ํ•ด๋‹น ๊ฐ„์„ ์„ ์„  ์‚ฌ์ดํด์„ ํ˜•์„ฑํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์„ ํƒํ•˜๊ณ  ๋‹ค์Œ์œผ๋กœ ๋„˜์–ด๊ฐ„๋‹ค.

  • Step 2

๋‘๋ฒˆ์งธ ๊ฐ„์„ ์„ ์„ ํƒํ–ˆ์„ ๋•Œ 3์ด ์„ ํƒ๋˜์ง€ ์•Š์€ ๊ทธ๋ฃน์˜ ์ •์ ์ด๋ฏ€๋กœ ์‚ฌ์ดํด ํ˜•์„ฑ์ด ๋˜์ง€ ์•Š๊ณ ,
๋‘๋ฒˆ์งธ ๊ฐ„์„  ๋˜ํ•œ ์„ ํƒํ•˜๊ณ  ๋„˜์–ด๊ฐ„๋‹ค.

  • Step 3

์„ธ๋ฒˆ์งธ ๊ฐ„์„ ์„ ์„ ํƒํ–ˆ์„ ๋•Œ 4๊ฐ€ ์„ ํƒ๋˜์ง€ ์•Š์€ ๊ทธ๋ฃน์˜ ์ •์ ์ด๋ฏ€๋กœ ์‚ฌ์ดํด์ด ํ˜•์„ฑ๋˜์ง€ ์•Š๊ณ ,
์„ ํƒํ•˜๊ณ  ๋„˜์–ด๊ฐ„๋‹ค.

  • Step 4

๋„ค๋ฒˆ์งธ ๊ฐ„์„ ์„ ์„ ํƒํ–ˆ์„ ๋•Œ 0์ด ์„ ํƒ๋˜์ง€ ์•Š์€ ๊ทธ๋ฃน์˜ ์ •์ ์ด๋ฏ€๋กœ ์‚ฌ์ดํด์ด ํ˜•์„ฑ๋˜์ง€ ์•Š๊ณ ,
์„ ํƒํ•˜๊ณ  ๋„˜์–ด๊ฐ„๋‹ค.

  • Step 5

๋‹ค์„ฏ๋ฒˆ์งธ ๊ฐ„์„ ์„ ์„ ํƒํ–ˆ์„ ๋•Œ 1๊ณผ 0 ๋ชจ๋‘ ์„ ํƒ๋œ ๊ทธ๋ฃน์˜ ์ •์ ์ด๋ฏ€๋กœ ์‚ฌ์ดํด์ด ํ˜•์„ฑ๋˜์–ด,
์„ ํƒํ•˜์ง€ ์•Š๊ณ  ๋„˜์–ด๊ฐ„๋‹ค.

  • Step 6

์—ฌ์„ฏ๋ฒˆ์งธ ๊ฐ„์„ ์„ ์„ ํƒํ–ˆ์„ ๋•Œ๋„ 2์™€ 3 ๋ชจ๋‘ ์„ ํƒ๋œ ๊ทธ๋ฃน์˜ ์ •์ ์ด๋ฏ€๋กœ ์‚ฌ์ดํด์ด ํ˜•์„ฑ๋˜์–ด,
์„ ํƒํ•˜์ง€ ์•Š๊ณ  ๋„˜์–ด๊ฐ„๋‹ค.

  • Step 7

๋งˆ์ง€๋ง‰์œผ๋กœ ์ผ๊ณฑ๋ฒˆ์งธ ๊ฐ„์„ ์„ ์„ ํƒํ–ˆ์„ ๋•Œ 5๊ฐ€ ์„ ํƒ๋˜์ง€ ์•Š์€ ๊ทธ๋ฃน์˜ ์ •์ ์ด๋ฏ€๋กœ ์‚ฌ์ดํด์ด ํ˜•์„ฑ๋˜์ง€ ์•Š๊ณ ,
์„ ํƒํ•˜๊ณ  ๋งˆ๋ฌด๋ฆฌํ•œ๋‹ค.

โšฝ๏ธ ์ฝ”๋“œ ๊ตฌํ˜„

### Kruskal
# union-find
def find_non_recursion(parent, x):
    while parent[x] != x:
        parent[x] = parent[parent[x]] # ๊ฒฝ๋กœ ์••์ถ•
        x = parent[x]
    return x

def find_recursion(parent, x):
		if parent[x] != x:
				parent[x] = find_recursion(parent, parent[x]) # ๊ฒฝ๋กœ ์••์ถ•
		return parent[x]

def union(parent, x, y):
    x_root = find(parent, x)
    y_root = find(parent, y)
    
    if x_root == y_root:
        return False
    parent[y_root] = x_root
    return True

# kruskal
def kruskal(v, graph):
    parent = [i for i in range(v+1)]
    graph.sort(key=lambda x: x[2])
    result = 0

    for a, b, weight in graph:
        if union(parent, a, b):
            result += weight
    return result

if __name__ == "__main__":
		v = 6
		inp = [(
    graph = [(1, 1, 2), (2, 1, 3), (2, 3, 4), (3, 2, 0), (4, 0, 1), (4, 2, 3), (6, 4, 5)]
    answer = kruskal(graph)
    print(answer)

๐ŸŽฑย Prim

ํ”„๋ฆผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ •์ ์„ ์ค‘์‹ฌ์œผ๋กœ ํ•˜๋Š” MST ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

โšฝ๏ธ ํ•ต์‹ฌ ๊ฐœ๋…

๋Œ€๋žต์ ์ธ ํ๋ฆ„์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  1. ์ดˆ๊ธฐ ์ •์  pq์— ์‚ฝ์ž…
    • ์šฐ์„ ์ˆœ์œ„ ํ(Priority Queue)๋ฅผ ์‚ฌ์šฉํ•ด ๋…ธ๋“œ ์„ ํƒ์„ ํšจ์œจ์ ์œผ๋กœ ๊ตฌํ˜„
    • ์ด ๋•Œ pq์—๋Š” ๊ฐ€์ค‘์น˜๊ฐ€ ์ฒซ๋ฒˆ์งธ ์ธ์ž๋กœ ์˜ค๋„๋ก (weight, node) ํ˜•์‹์œผ๋กœ ์‚ฝ์ž…ํ•œ๋‹ค.
  2. pq์—์„œ popํ•œ ์ •์ ์ด ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌ ํ›„ 3๋ฒˆ ์ง„ํ–‰
    • ๋ฐฉ๋ฌธํ–ˆ๋‹ค๋ฉด ์‚ฌ์ดํด์„ ํ˜•์„ฑํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ ์„ ํƒํ•˜์ง€ ์•Š์Œ โ†’ 4๋ฒˆ ์ง„ํ–‰
  3. ํ˜„์žฌ ์ •์ ๊ณผ ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ์ •์  ์ค‘ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์„ pq์— ์‚ฝ์ž… โžก๏ธย O(E log V)
  4. 2๋ฒˆ์œผ๋กœ ๋Œ์•„๊ฐ€ pq๊ฐ€ ๋นŒ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต โžก๏ธย O(E)

ํ•œ ๋…ธ๋“œ์— ์ตœ๋Œ€๋กœ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ฐ„์„ ์˜ ์ˆ˜๋Š” ์ „์ฒด ๊ฐ„์„ ์˜ ์ˆ˜์ธ E์ด๊ณ , ์šฐ์„ ์ˆœ์œ„ ํ๋ฅผ ์ด์šฉํ•ด ์‚ฝ์ž…๊ณผ ์‚ญ์ œ๋ฅผ ๊ตฌํ˜„ํ–ˆ์„ ๋•Œ ์‚ฝ์ž…, ์‚ญ์ œ์— ์†Œ์š”๋˜๋Š” ์‹œ๊ฐ„์€ ์ตœ๋Œ€ log V์ด๋ฏ€๋กœ ์ „์ฒด ์‹œ๊ฐ„๋ณต์žก๋„๋Š” O(E log V)์ด๋‹ค.

โšฝ๏ธ ์ž์„ธํ•œ ํ๋ฆ„

์œ„ ๋‹จ๊ณ„๋“ค์„ ์ฐจ๋ก€๋กœ ์‚ดํŽด๋ณด์ž.

  • Step 0 (์ดˆ๊ธฐ ๋‹จ๊ณ„)

์ดˆ๊ธฐ ๋…ธ๋“œ๋ฅผ 0์œผ๋กœ ์„ค์ •ํ•˜๊ณ , 0์„ pq์— ์‚ฝ์ž…ํ•œ ๋’ค ์‹œ์ž‘ํ•œ๋‹ค. ์ด๋•Œ ๊ฐ€์ค‘์น˜๋Š” 0์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.
pq์—์„œ popํ•˜๋ฉด ์ดˆ๊ธฐ๊ฐ’์ธ (0, 0)์ด ๋‚˜์˜ค๊ณ , ์ดˆ๊ธฐ์—๋Š” ์–ด๋–ค ์ •์ ๋„ ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌ(์ดˆ๋ก์ƒ‰) ๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ 0์„ ์„ ํƒํ•œ๋‹ค.
๊ทธ๋ฆฌ๊ณ  0๊ณผ ์—ฐ๊ฒฐ๋œ ์ •์ ์ธ 1, 2 ๋ชจ๋‘ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ด๋ฏ€๋กœ pq์— pushํ•œ๋‹ค.

  • Step 1

pq์—์„œ popํ•˜๋ฉด (3, 2)๊ฐ€ ๋‚˜์˜ค๊ณ , 2๋Š” ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ด๋ฏ€๋กœ ์„ ํƒํ•˜๊ณ  ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌํ•œ๋‹ค.
2์™€ ์—ฐ๊ฒฐ๋œ 0, 1, 3 ์ค‘์—์„œ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ธ 1, 3์„ pq์— pushํ•œ๋‹ค.

  • Step 2

pq์—์„œ popํ•˜๋ฉด (1, 1)์ด ๋‚˜์˜ค๊ณ , 1์€ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ด๋ฏ€๋กœ ์„ ํƒํ•˜๊ณ  ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌํ•œ๋‹ค.
1๊ณผ ์—ฐ๊ฒฐ๋œ 0, 2, 3 ์ค‘์—์„œ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ธ 3์„ pq์— pushํ•œ๋‹ค.

  • Step 3

pq์—์„œ popํ•˜๋ฉด (2, 3)์ด ๋‚˜์˜ค๊ณ , 3์€ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ด๋ฏ€๋กœ ์„ ํƒํ•˜๊ณ  ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌํ•œ๋‹ค.
3๊ณผ ์—ฐ๊ฒฐ๋œ 1, 2, 4 ์ค‘์—์„œ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ธ 4๋ฅผ pq์— pushํ•œ๋‹ค.

  • Step 4

pq์—์„œ popํ•˜๋ฉด (2, 4)๊ฐ€ ๋‚˜์˜ค๊ณ , 4๋Š” ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ด๋ฏ€๋กœ ์„ ํƒํ•˜๊ณ  ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌํ•œ๋‹ค.
4์™€ ์—ฐ๊ฒฐ๋œ 3, 5 ์ค‘์—์„œ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ธ 5๋ฅผ pq์— pushํ•œ๋‹ค.

  • Step 5

pq์—์„œ popํ•˜๋ฉด (4, 1)์ด ๋‚˜์˜ค์ง€๋งŒ 1์€ ๋ฐฉ๋ฌธํ•œ ์ •์ ์ด๋ฏ€๋กœ ์„ ํƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
๋‹ค์‹œ popํ•˜๋ฉด (4, 3)์ด ๋‚˜์˜ค์ง€๋งŒ 3 ๋˜ํ•œ ๋ฐฉ๋ฌธํ•œ ์ •์ ์ด๋ฏ€๋กœ ์„ ํƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
๋‹ค์‹œ popํ•˜๋ฉด (6, 5)๊ฐ€ ๋‚˜์˜ค๊ณ , 5๋Š” ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์ ์ด๋ฏ€๋กœ ์„ ํƒํ•˜๊ณ  ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌํ•œ๋‹ค.
5์™€ ์—ฐ๊ฒฐ๋œ 4๋Š” ๋ฐฉ๋ฌธํ•œ ์ •์ ์ด๋ฏ€๋กœ ์•„๋ฌด๊ฒƒ๋„ pushํ•˜์ง€ ์•Š๋Š”๋‹ค.

pq๊ฐ€ ๋น„์—ˆ์œผ๋ฏ€๋กœ ๋ฐ˜๋ณต๋ฌธ์„ ์ข…๋ฃŒํ•œ๋‹ค.

โšฝ๏ธ ์ฝ”๋“œ ๊ตฌํ˜„

import heapq
from collections import defaultdict
### Prim
def prim(graph):
    v = len(graph)
    visited = [0 for _ in range(v+1)]
    pq = []

    # initial setting
    heapq.heappush(pq, (0, 1))
    result = 0

    # repitition
    while pq:
        weight, x = heapq.heappop(pq)

        if visited[x]:
            continue

        visited[x] = 1
        result += weight

        for nx, weight in graph[x]:
            if not visited[nx]:
                heapq.heappush(pq, (weight, nx))
    return result

๐ŸŽฑย ์–ด๋–ค ์ฐจ์ด์ ์ด ์žˆ์„๊นŒ?

Kruskal (non-recursion)Kruskal (recursion)Prim
๊ธฐ์ค€๊ฐ„์„ ๊ฐ„์„ ๋…ธ๋“œ
์‚ฌ์ดํด ๋ฐฉ์ง€ ๋ฐฉ์‹Union-Find (non-recursion)Union-Find (recursion)visited ๋ฐฐ์—ด
์‚ฌ์šฉ ์ž๋ฃŒ๊ตฌ์กฐ์ •๋ ฌ + Union-Find์ •๋ ฌ + Union-FindPriority Queue
์‚ฌ์šฉ ์ƒํ™ฉ์ •์ ์— ๋น„ํ•ด ๊ฐ„์„ ์ด ๋งŽ์€ ๊ฒฝ์šฐ์ •์ ์— ๋น„ํ•ด ๊ฐ„์„ ์ด ๋งŽ์€ ๊ฒฝ์šฐ๊ฐ„์„ ์— ๋น„ํ•ด ์ •์ ์ด ๋งŽ์€ ๊ฒฝ์šฐ
์‹œ๊ฐ„๋ณต์žก๋„O(E log E)O(E log E)O(E log V)
์ฃผ์˜์‚ฌํ•ญโŒ์žฌ๊ท€ ๊นŠ์ด ์ œํ•œ์— ์ฃผ์˜โŒ

๊ฐ„๋‹จํ•˜๊ฒŒ ํ…Œ์ด๋ธ”์„ ํ†ตํ•ด ์ฐจ์ด์ ์„ ์ •๋ฆฌํ•ด๋ดค๋‹ค.
๋‚˜๊ฐ™์œผ๋ฉด ์›ฌ๋งŒํ•˜๋ฉด Kruskal ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•  ๊ฒƒ ๊ฐ™๊ธด ํ•˜๋‹ค.

profile
๋ฐ๊ตด๋ฐ๊ตด ๊ตฌ๋ฅด๋Š” ๊ฐœ๋ฐœ์ž ์ง€๋ง์ƒ

0๊ฐœ์˜ ๋Œ“๊ธ€