Chuncheonian

asdfdsfsdafsdfsadfsdfsdfasdfsdfsdf

No preview for this file type
1 +# Floyd Warshall Algorithm (플로이드-워셜)
2 +
3 +> 모든 정점 사이의 최단 거리를 찾는 탐색 알고리즘
4 +
5 +## 아이디어
6 +
7 +* 두 정점 사이의 최단 경로는 **다른 한 정점을 거치거나**, **거치지 않는 경로** 중 하나이다.
8 +
9 +* 만약 경유지를 거친다면 최단 경로를 이루는 부분 경로 역시 최단 경로이다. 바꿔 말해 A - B의 최단 경로가 A-K-B라면 A-K와 K-B도 각각 최단 경로이다. *(Optimal Substructure)*
10 +
11 +## 알고리즘 설계 및 구현
12 +
13 +1. 한 정점에서 다른 정점으로 바로 갈 수 있으면 최소거리를, 갈 수 없으면 INF값을 담고 있는 2차원 행렬 D을 초기화한다.
14 +
15 +2. 각 정점이 경유지 K를 지날 때마다 최단 거리를 계산하여 행렬 D를 갱신한다.
16 +
17 +3. Dynamic Programming으로 해결하며, 점화식은 `D[i][j] = min(D[i][j], D[i][k] + D[k][j])` 이다.
18 +
19 +## 시간 복잡도
20 +
21 +모든 가능한 경유지에 대해서 모든 정점 모든 정점으로 가는 최단 거리를 확인하므로, 시간복잡도는 `O(n^3)` 이다.
22 +
23 +## 예시
24 +
25 +<p align="center">
26 + <img src = "./images/floyd_1.png" width="40%" alt="floyd_1">
27 +</p>
28 +
29 +<p align="center">
30 + <img src = "./images/floyd_2.png" width="40%" alt="floyd_2">
31 +</p>
32 +
33 +## 코드 - Python
34 +
35 +``` python
36 +import copy
37 +
38 +# Floyd-Warshall Algorithm: 모든 정점에서 모든 정점까지의 최단 경로 알고리즘
39 +def floyd_warshall(g: list[list[int]], n: int) -> list[list[int]:
40 + dist = copy.deepcopy(g) # dist: 최단 경로의 길이를 담은 행렬
41 +
42 + for k in range(0, n): # 거치는 점
43 + for i in range(0, n): # 시작점
44 + for j in range(0, n): # 끝점
45 + dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
46 + return dist
47 +
48 +# print 2-D Matrix
49 +def printMatrix(d: list[list[int]]) -> None:
50 + n = len(d[0])
51 +
52 + for i in range(0, n):
53 + for j in range(0, n):
54 + print(d[i][j], end=' ')
55 + print()
56 +
57 +# Testcase
58 +INF = 1000
59 +g = [ [0, 1, INF, 1, 5],
60 + [9, 0, 3, 2, INF],
61 + [INF, INF, 0, 4, INF],
62 + [INF, INF, 2, 0, 3],
63 + [3, INF, INF, INF, 0] ]
64 +
65 +dist = floyd_warshall(g, 5)
66 +printMatrix(dist)
67 +```
68 +
69 +## Floyd's Algorithm을 통한 최단 경로 출력
70 +
71 +Optimal Substructure을 활용하면 경유하는 정점들을 알 수 있다.
72 +
73 +P[i][j] = 중간에 정점이 없으면 0, 있으면 그 중 가장 큰 인덱스
74 +
75 +### 예시
76 +
77 +<p align="center">
78 + <img src = "./images/floyd_3.png" width="40%" alt="floyd_3">
79 +</p>
80 +
81 +```
82 + path(5, 3) = 4
83 + path(5, 4) = 1
84 + path(5, 1) = 0
85 + v1
86 + path(1, 4) = 0
87 + v4
88 + path(4, 3) = 0
89 +
90 +즉, v5에서 v3까지 최단 경로는 v5 -> v1 -> v4 -> v3 이다.
91 +```
92 +
93 +### 코드
94 +
95 +```python
96 +# Floyd-Warshall 알고리즘을 통한 최단 경로를 구성하는 정점 기록
97 +def floyd_warshall_2(g: list[list[int]], n: int):
98 + dist = copy.deepcopy(g)
99 + p = [[0] * n for _ in range(n)] # p: 중간에 정점이 없으면 0, 있으면 그 중 가장 큰 인덱스를 포함한 행렬
100 +
101 + for k in range(0, n):
102 + for i in range(0, n):
103 + for j in range(0, n):
104 + if dist[i][k] + dist[k][j] < dist[i][j]:
105 + p[i][j] = k + 1 # 경로 중 가장 큰 인덱스 저장
106 + dist[i][j] = dist[i][k] + dist[k][j]
107 + return dist, p
108 +
109 +# print 2-D Matrix
110 +def printMatrix(d: list[list[int]]) -> None:
111 + n = len(d[0])
112 +
113 + for i in range(0, n):
114 + for j in range(0, n):
115 + print(d[i][j], end=' ')
116 + print()
117 +
118 +# 특정 두 정점 사이의 최단 경로 출력
119 +def printPath(p: list[list[int]], q: int, r: int) -> None:
120 + if p[q-1][r-1] != 0: # 최단 경로가 경유지를 지날 경우
121 + printPath(p, q, p[q-1][r-1]) # 시작 정점에서 겅유하는 정점까지의 경로 검사
122 + print(f'v{p[q-1][r-1]}', end=' ')
123 + printPath(p, p[q-1][r-1], r) # 겅유하는 정점에서 끝 정점까지의 경로 검사
124 +
125 +# Testcase
126 +INF = 1000
127 +g = [ [0, 1, INF, 1, 5],
128 + [9, 0, 3, 2, INF],
129 + [INF, INF, 0, 4, INF],
130 + [INF, INF, 2, 0, 3],
131 + [3, INF, INF, INF, 0] ]
132 +
133 +d, p = floyd_warshall_2(g, 5)
134 +print()
135 +printMatrix(d)
136 +print()
137 +printMatrix(p)
138 +print()
139 +printPath(p, 5, 3)
140 +```
1 +# Dongyoung Kwon @Chuncheonian (ehddud2468@gmail.com)
2 +import copy
3 +
4 +# Floyd-Warshall Algorithm: 모든 정점에서 모든 정점까지의 최단 경로
5 +def floyd_warshall(g: list[list[int]], n: int) -> list[list[int]]:
6 + dist = copy.deepcopy(g) # dist: 최단 경로의 길이를 담은 행렬
7 +
8 + for k in range(0, n): # 거치는 점
9 + for i in range(0, n): # 시작점
10 + for j in range(0, n): # 끝점
11 + dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
12 + return dist
13 +
14 +# Floyd-Warshall 알고리즘을 통한 최단 경로를 구성하는 정점 기록
15 +def floyd_warshall_2(g: list[list[int]], n: int):
16 + dist = copy.deepcopy(g)
17 + p = [[0] * n for _ in range(n)] # p: 중간에 정점이 없으면 0, 있으면 그 중 가장 큰 인덱스를 포함한 행렬
18 +
19 + for k in range(0, n):
20 + for i in range(0, n):
21 + for j in range(0, n):
22 + if dist[i][k] + dist[k][j] < dist[i][j]:
23 + p[i][j] = k + 1 # 경로 중 가장 큰 인덱스 저장
24 + dist[i][j] = dist[i][k] + dist[k][j]
25 + return dist, p
26 +
27 +# print 2-D Matrix
28 +def printMatrix(d: list[list[int]]) -> None:
29 + n = len(d[0])
30 +
31 + for i in range(0, n):
32 + for j in range(0, n):
33 + print(d[i][j], end=' ')
34 + print()
35 +
36 +# 특정 두 정점 사이의 최단 경로 출력
37 +def printPath(p: list[list[int]], q: int, r: int) -> None:
38 + if p[q-1][r-1] != 0: # 최단 경로가 경유지를 지날 경우
39 + printPath(p, q, p[q-1][r-1]) # 시작 정점에서 겅유하는 정점까지의 경로 검사
40 + print(f'v{p[q-1][r-1]}', end=' ')
41 + printPath(p, p[q-1][r-1], r) # 겅유하는 정점에서 끝 정점까지의 경로 검사
42 +
43 +# Testcase
44 +INF = 1000
45 +g = [ [0, 1, INF, 1, 5],
46 + [9, 0, 3, 2, INF],
47 + [INF, INF, 0, 4, INF],
48 + [INF, INF, 2, 0, 3],
49 + [3, INF, INF, INF, 0] ]
50 +
51 +d, p = floyd_warshall_2(g, 5)
52 +print()
53 +printMatrix(d)
54 +print()
55 +printMatrix(p)
56 +print()
57 +printPath(p, 5, 3)
...\ No newline at end of file ...\ No newline at end of file
No preview for this file type