[자료구조] 그래프 -4
- 본문과 관련하여 실습한 전체코드는 리파지토리에 별도 작성하였습니다.
- https://github.com/ejImDev/data_structure_study.git
최소신장트리
- 신장트리(Spanning Tree) : 주어진 그래프가 하나의 연결성분으로 구성되어 있을 때, 그래프의 모든 정점들을 싸이클 없이 연결하는 부분 그래프
- 최소신장트리(Minimum Spanning Tree, MST) : 하나의 연결성분으로 이루어진 무방향 가중치 그래프에서 간선의 가중치의 합이 최소인 신장 트리
- MST를 찾는 대표적인 알고리즘은 Kruskal, Prim, Sollin 알고리즘
- 모두 그리디(Greedy) 알고리즘
- 모두 그리디(Greedy) 알고리즘
- 그리디 알고리즘 : 최적해(최솟값 또는 최댓값)를 찾는 문제를 해결하기 위한 알고리즘 방식들 중 하나로서, 알고리즘의 선택이 항상 ‘욕심내어’ 지역적인 최솟값(또는 최댓값)을 선택하며, 이러한 부분적인 선택을 축적하여 최적해를 찾음
Kruskal 알고리즘
- 간선들을 가중치가 감소하지 않는 순서로 정렬한 후, 가장 가중치가 작은 간선을 트리에 추가하여 싸이클을 만들지 않으면 트리 간선으로 선택하고, 싸이클을 만들면 버리는 일을 반복하여 N-1개의 간선이 선택되었을 때 알고리즘을 종료
- N은 그래프 정점의 수
- N은 그래프 정점의 수
-
Kruskal 알고리즘이 그리디 알고리즘인 이유 : 남아있는 (정렬된) 간선들 중에서 항상 ‘욕심 내어’ 가중치가 가장 작은 간선을 가져오기 때문
- 순서
- 가중치가 감소하지 않는 순서로 간선 리스트 L을 만든다
- while(트리의 간선 수 < N-1)
- L에서 가장 작은 가중치를 가진 간선 e를 가져오고, e에서 L을 제거
- if(간선 e가 T에 추가하여 싸이클을 만들지 않으면)
- 간선 e를 T에 추가
- 가중치가 감소하지 않는 순서로 간선 리스트 L을 만든다
Dijkstra 알고리즘
- 최단경로 찾기는 주어진 가중치그래프에서 출발점으로부터 도착점까지의 최단경로를 찾는 문제
-
Dijkstra 알고리즘 : 출발점으로부터 각 정점까지의 최단거리 및 경로를 계산
- 순서
- 배열 D를 ∞로 초기화시킨다. 단, D[s]=0이다.
- for(k=0; k<N; k++)
- 방문 안된 각 정점 i에 대해 D[i]가 최소인 정점 minVertex를 찾고, 방문한다
- for(minVertex에 인접한 각 정점 w에 대해서)
- if(w가 방문 안된 정점이면)
- if(D[minVertex] + 간선(minVertex, w)의 가중치 < D[w])
- D[w] = D[minVertex]+간선(minVertex, w)의 가중치 // 간선완화
- previous[w] = minVertex
- 배열 D를 ∞로 초기화시킨다. 단, D[s]=0이다.
### 수행시간
- Dijkstra 알고리즘은 N번의 반복을 거쳐 minVertex를 찾고 minVertex에 인접하면서 방문되지 않은 정점들에 대한 간선완화를 시도
- 이후 배열 D에서 minVertex를 탐색하는데 O(N) 시간이 소요되고, minVertex에 인접한 정점들을 검사하여 D의 원소들을 갱신하므로 추가로 O(N) 시간이 소요
- 따라서 총 수행시간은 Nx(O(N)+O(N)) = O(N^2^)
Bellman-Foad 알고리즘
- Dijkstra 알고리즘은 음수가중치를 가진 그래프에서 최단경로를 찾지 못함
- Bellman-Foad 알고리즘은 음수가중치 그래프에서도 문제 없이 최단경로를 찾을 수 있음
- 단, 입력그래프에 싸이클 상의 간선들의 가중치 합이 0보다 작은 음수싸이킬이 없어야 함
- 만약 어떤 경로에 음수싸이클이 존재한다면, 음수싸이클을 반복할 수록 경로의 길이가 더 짧아지는 모순이 발생하기 때문
- 만약 어떤 경로에 음수싸이클이 존재한다면, 음수싸이클을 반복할 수록 경로의 길이가 더 짧아지는 모순이 발생하기 때문
-
핵심아이디어 : 입력그래프에 음수싸이클이 없으므로 출발점에서 각 정점까지 최단경로 상에 있는 간선의 수는 최대 N-1개이다. 따라서 각 정점에 대해 간선완화를 N-1번 수행하면 더 이상 간선완화로 인한 갱신이 있을 수 없다.
- 순서
- 배열 D를 ∞로 초기화한다. 단, D[s] = 0, s는 출발점
- for(k=0; k<N-1; k++)
- 각 (i,j)에 대하여
- if(D[j] > (D[i]+(i,j)의 가중치))
- D[j] = D[i]+(i,j)의 가중치 // 간선완화
- previous[j] = i
- 배열 D를 ∞로 초기화한다. 단, D[s] = 0, s는 출발점
참고 자료 : ‘경기대학교 소프트웨어중심대학사업단 - JAVA 자료구조’ https://youtu.be/yZD3up52MRE