그래프 내의 모든 정점을 포함하는 트리
n개의 정점으로 이루어진 무방향 그래프에서 n-1개의 간선으로 이루어진 트리
무방향 가중치 그래프에서 신장 트리를 구성하는 간선들의 가중치 합이 최소인 신장 트리
가중치의 합이 최소여야 한다.
n개의 정점을 가지는 그래프에 대해 반드시 n-1개의 간선만을 사용해야한다.
사이클이 포함되면 안된다.
그래프에서 최소 비용을 구할때 활용
하나의 정점에서 출발하여 연결된 간선들 중 하나씩 선택하면서 MST를 만들어나가는 방식
V,E = map(int,input().split())
adj = {i:[] for i in range(V)}
for i in range(E):
s,e,c = map(int,input().split())
adj[s].append([e,c])
adj[e].append([s,c])
INF = float('inf')
cnt = 0
key = [INF]*V
mst = [False]*V
p = [-1]*V
p[0] = 0
mst[0] = True
key[0] = 0
u = 0
while cnt < V-1:
for w,c in adj[u]:
if not mst[w] and c < key[w]:
key[w] = c
p[w] = u
min = INF
for i in range(V):
if key[i] < min:
min = key[i]
u = i
cnt += 1
import heapq
V,E = map(int,input().split())
adj = {i:[] for i in range(V)}
for i in range(E):
s,e,c = map(int,input().split())
adj[s].append([e,c])
adj[e].append([s,c])
# key, mst, 우선순위 큐 준비
INF = float('inf')
key = [INF]*V
mst = [False]*V
pq=[]
#시작 정점 선택 : 0(임의)
key[0] = result = 0
#큐에 시작 정점을 넣음 => (key, 정점인덱스) #우선순위 큐 -> 이진힙 -> heapq 라이브러리 사용
heapq.heappush(pq, (0,0))#우선순위큐 -> 원소의 첫번째 요소 -> key를 우선순위로 #힙의 구조 유지하면서 하나의 원소 넣음
while pq:
#최솟값 찾기
k, node = heapq.heappop(pq)
if mst[node]: continue
#mst로 선택
mst[node] = True
result += k
#key 갱신 => key 배열/ 큐
for dest,wt in adj[node]: #(목적지,가중치)
if not mst[dest] and wt < key[dest]:
key[dest] = wt
#큐 갱신 => 새로운 (key,정점) 삽입 => 필요없는 원소는 스킵
heapq.heappush(pq,(key[dest],dest))
탐욕적인 방법을 이용하여 네트워크(가중치를 간선에 할당한 그래프)의 모든 정점을 최소 비용으로 연결하는 최적 해답을 구하는 것
간선 정보가 담긴 리스트에서 가중치를 기준으로 오름차순 정렬
가중치가 가장 낮은 간선부터 선택하면서 트리를 확장
n-1개의 간선이 선택될 때까지 위 과정을 반복
def make_set(x):
p[x] = x
def find_set(x):
if x == p[x]:
return x
else:
p[x] = find_set(p[x])
return p[x]
def union(x,y):
px = find_set(x)
py = find_set(y)
if rank[px] > rank[py]:
p[py] = px
else:
p[px] = py
if p[px] == p[py]:
rank[py] += 1
#union이 끝나면 흡수된 트리의 종속되어있는 자식들의 대표자도 흡수한 노드로 바꿔줘야하기 때문에 find_set으로 한번 씩 돌림
for i in range(V):
find_set(i)
V,E = map(int,input().split())
edges = [list(map(int,input().split())) for _ in range(E)]
#간선을 간선 가중치를 기준으로 정렬
edges.sort(key=lambda x:x[2]) #x를 넣으면 x[2]를 반환
#make_set : 모든 정점에 대해 집합 생성
p = [0]*V
rank = [0]*V
for i in range(V):
make_set(i)
cnt = result = 0
mst = []
#모든 간선에 대해서 반복 -> V-1개의 간선이 선택될 때까지(모든 정점이 연결되려면 간선의 갯수는 V-1개여야하므로)
for i in range(E):
s,e,c = edges[i][0],edges[i][1],edges[i][2]
#사이클이면 스킵 : 간선의 두 정점이 서로 같은 집합이면 => find_set
if finde_set(s) == find_set(e): continue
#간선 선택
#=> mst에 간선 정보 더하기 / 두 정점을 합친다 => union
result += c
mst.append(edges[i])
union(s,e)
cnt += 1
if cnt == V-1: break #간선을 V-1개 선택했으면 종료
간선의 가중치가 있는 그래프에서 두 정점 사이의 경로들 중 간선의 가중치의 합이 최소 인 경로
#다익스트라 + 인접리스트
V,E = map(int,input().split())
adj = {i:[] for i in range(V)}
for i in range(E):
s,e,c = map(int, input().split())
adj[s].append([e,c])
INF=float('inf')
#dist, selected 배열 준비
dist = [INF]*V
selected = [False]*V
dist[0] = 0 #시작점 선택
cnt = 0
while cnt < V: #모든 정점이 선택될때까지
#dist가 최소인 정점 찾기
min = INF
for i in range(V):
if not selected[i] and dist[i]<min:
min = dist[i]
u = i #아직 선택되지 않고 dist의 값이 최소인 정점: u
#정점 u의 최단거리 결정
selected[u] = True
cnt += 1
#정점 u에 인접한 정점에 대해서 간선완화
for w,cost in adj[u]: #도착 정점, 가중치
if dist[u]+cost < dist[w]:
dist[w] = dist[u]+cost
print(dist)
다익스트라 알고리즘은 특정 두 노드 사이의 최단 경로만 알 수 있다. 하지만 플로이드 워샬 알고리즘은 모든 정점들에 대한 최단 경로를 알 수 있기 때문에 알아두면 편리한 알고리즘이다. 이 알고리즘은 모든 점을 각각 중간 지점을 정했을 때, 중간 지점 ~ 시작 지점까지의 최단 경로, 중간 지점 ~ 도착 지점까지의 최단 경로를 더해서 시작 지점부터 도착 지점까지의 최단 경로를 구하는 방식이다.
O(n^3)
각 정점들간의 최단 경로를 담아두기 위한 2차원 리스트를 준비한다.
행과 열 번호가 같은 자기 자신은 거리가 0이므로 0으로 초기화 하고, 나머지 경로는 inf로 초기화한다.
중간 지점을 설정하기 위해 1부터 n까지 for문을 순회한다.
중간 지점을 m이라 두고, 내부에서 2중 for문(i: 시작 지점, j: 도착 지점)을 순회한다.
시작~중간 + 중간~도착이 최소가 되면 최솟값으로 갱신
3중 for문을 돌고나면 모든 정점에 대한 최단 경로를 알 수 있다.
INF = float('inf')
dist = [[INF]*(n+1) for _ in range(n+1)]
for i in range(1,n+1):
dist[i][i] = 0
for u,w,c in fares:
dist[u][w] = c
dist[w][u] = c
for m in range(1,n+1):
for i in range(1,n+1):
for j in range(1,n+1):
val = dist[i][m] + dist[m][j]
if val < dist[i][j]:
dist[i][j] = val