🧠𝗔𝗹𝗴𝗼𝗿𝗶𝘁𝗵𝗺/💛 백준
[백준/최소 스패닝 트리] 1197번. 최소 스패닝 트리, 1922번 네트워크 연결(Python)
안오늘
2021. 7. 30. 10:24
문제
https://www.acmicpc.net/problem/1197
https://www.acmicpc.net/problem/1922
풀이
최소 스패닝 트리(Minimum Spanning Tree)
: 주어진 그래프의 모든 정점들을 연결하는 부분 그래프 중에서 그 가중치의 합이 최소인 트리
MST를 구하는 방법은 크루스칼 알고리즘과 프림알고리즘이 있다.
크루스칼 알고리즘 : 모든 간선에 대해 가장 가중치가 작은 간선부터 하나씩 이어나가며 모든 정점을 방문하는 방법
- 사이클이 발생하면 그 간선은 건너 뛰어야 한다.
- 사이클 발생유무를 체크하기 위해서는 유니온 파인드 구조를 사용한다.
- 간선이 연결하는 두 개의 노드가 같은 집합에 속하면? 사이클이 존재
- 간선이 연결하는 두 개의 노드가 같은 집합에 속하지 않는다면? 두 간선을 연결(union)하고 총 가중치에 현재 간선의 가중치 합산
- 시간 복잡도는 O(ElogE)이다.
프림 알고리즘 : 정점을 기준으로 인접한 간선들 중 가중치가 가장 작은 간선의 정점으로 이동하는 방법
- PQ를 이용해 구현한다.
- BFS와 유사하다.
다음은 유니온파인드로 푼 최소스패닝트리 코드이다.
두 문제는 풀이가 똑같았다!
# -*- coding: utf8 -*-
import heapq
from sys import stdin
def getParent(parent, x):
# 부모노드를 찾는 함수
if parent[x] == x:
return x
parent[x] = getParent(parent, parent[x])
return parent[x]
def unionParent(parent, a, b):
# 두 부모노드를 합치는 함수
a = getParent(parent, a)
b = getParent(parent, b)
if a < b:
parent[b] = a
else:
parent[a] = b
def findParent(parent, a, b):
# 같은 부모를 가지는지 확인
a = getParent(parent, a)
b = getParent(parent, b)
if a == b:
return 1
return 0
def solution(V, E):
# 자기 자신을 부모로 설정
parent = [i for i in range(V+1)]
edges = []
sum = 0
for _ in range(E):
a, b, cost = map(int, stdin.readline().rstrip().split(' '))
edges.append([cost, a, b])
edges.sort(key=lambda x: x[0]) # 가중치가 작은 순서대로 정렬
for cost, a, b in edges:
if not findParent(parent, a, b): # 부모가 다르다는 것은 사이클이 생기지 않는다는 것을 의미
unionParent(parent, a, b)
sum += cost
# 부모가 같으면 가중치가 작더라도 pass
return sum
V, E = map(int, stdin.readline().rstrip().split(' '))
print(solution(V, E))