[알고리즘/C++] 플로이드-워셜(Floyd-Warshall) 알고리즘
2023. 8. 3. 23:57ㆍAlgorithm
플로이드 워셜(Floyd-Warshall) 알고리즘은 거리 정보를 담는 행렬을 이용하여
모든 노드 간의 최단 경로를 구하는 알고리즘이다.
void floydWarshall(vector<vector<int>>& distance, vector<vector<pair<int, int>>> adj) {
for (int i = 0; i < distance.size(); i++) {
for (int j = 0; j < distance.size(); j++) {
if (i == j) {
distance[i][j] = 0;
}
else {
distance[i][j] = 100;
}
}
}
for (int i = 1; i < adj.size(); i++) {
for (int j = 0; j < adj[i].size(); j++) {
distance[i][adj[i][j].first] = adj[i][j].second;
}
}
for (int k = 1; k < adj.size(); k++) {
for (int i = 1; i < adj.size(); i++) {
for (int j = 1; j < adj.size(); j++) {
if (distance[i][j] > distance[i][k] + distance[k][j]) {
distance[i][j] = distance[i][k] + distance[k][j];
}
}
}
}
}
전체 코드는 위와 같다.
for (int i = 0; i < distance.size(); i++) {
for (int j = 0; j < distance.size(); j++) {
if (i == j) {
distance[i][j] = 0;
}
else {
distance[i][j] = 100;
}
}
}
먼저 distance 행렬의 대각 성분을 0으로, 나머지 요소들을 임의의 큰 값으로 초기화한다.
distance[start][end] = 8 이라는 의미는 start 노드에서 end 노드까지의 거리가 8이라는 의미이다.
이 요소에 알고리즘을 통해서 최단 거리를 담아내야한다.
for (int i = 1; i < adj.size(); i++) {
for (int j = 0; j < adj[i].size(); j++) {
distance[i][adj[i][j].first] = adj[i][j].second;
}
}
처음에는 인접 리스트의 정보를 통해서 직접 이웃의 노드의 가중치를 초기 거리로 갱신한다.
직접 이웃한 노드가 아니라면 해당 요소의 정보 업데이트는 이루어지지 않는다.
for (int k = 1; k < adj.size(); k++) {
for (int i = 1; i < adj.size(); i++) {
for (int j = 1; j < adj.size(); j++) {
if (distance[i][j] > distance[i][k] + distance[k][j]) {
distance[i][j] = distance[i][k] + distance[k][j];
}
}
}
}
distance의 각 요소에는 노드 a(행) 에서 노드 b(열) 까지의 거리 정보를 담고 있으므로
중간 노드 k를 거쳐서 더 가까워질 수 있으면 k를 경유한 더 짧은 길이로 갱신한다.
행렬 전체를 순회하는 과정이 노드의 갯수만큼(중간 노드로 선정 가능한 경우의 수)의 횟수만큼 반복된다.
시간 복잡도는 O(n^3)이므로 그래프의 크기가 짧은 경우에만 사용하는 것이 좋다.
void initGraph2(vector<vector<pair<int,int>>>& adj) {
adj.push_back({ {0, 0} });
//sentinel node
adj.push_back({ {2, 5}, {4, 9}, {5, 1} });
adj.push_back({ {1, 5}, {3, 2} });
adj.push_back({ {2, 2}, {4, 6} });
adj.push_back({ {1, 9}, {3, 6}, {5, 2} });
adj.push_back({ {1, 1}, {4, 2} });
}
그래프의 최초 생성하는 함수이다.
vector<vector<pair<int, int>>> adj;
//each node has several (neighbor, weight) pair.
initGraph2(adj);
//make adjacent matrix
vi temp(6, 0);
//노드의 갯수가 5개. 보초값 1개 추가.
vector<vi> distance(6, temp);
floydWarshall(distance, adj);
print2DVec(distance);
0 100 100 100 100 100
100 0 5 7 3 1
100 5 0 2 8 6
100 7 2 0 6 8
100 3 8 6 0 2
100 1 6 8 2 0
//첫 행과 첫 열은 sentinel value
'Algorithm' 카테고리의 다른 글
[알고리즘/C++] 크루스칼 알고리즘(Kruskal Algorithm) (0) | 2023.08.04 |
---|---|
[알고리즘/C++] 플로이드(Floyd) - 그래프 내에서 사이클 찾기 (0) | 2023.08.04 |
[알고리즘/C++] 다익스트라 알고리즘(Dijkstra's Algorithm) (0) | 2023.08.03 |
[알고리즘/C++] 최단 경로 찾기 - 벨만-포드 알고리즘(Bellman-Ford) (0) | 2023.08.03 |
[알고리즘/C++] 그래프 순회 - 너비 우선 탐색(BFS) (0) | 2023.08.03 |