Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ff03a0a

Browse files
committedMay 28, 2023
설명 수정
1 parent 6a00264 commit ff03a0a

File tree

11 files changed

+150
-106
lines changed

11 files changed

+150
-106
lines changed
 

‎day11/README.md

Lines changed: 150 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
**최단 경로 알고리즘**은 주어진 그래프에서 주어진 두 정점을 연결하는 가장 짧은 경로의 길이를 찾는 알고리즘입니다.
44

5-
가중치가 없는 그래프에서는 너비 우선 탐색으로 구할 수 있었습니다.
5+
이전에 살펴봤다시피 가중치가 없는 그래프에서는 너비 우선 탐색으로 구할 수 있었습니다.
66

77
여기서는 가중치가 있는 그래프만을 다루며, 음수 가중치를 갖는 간선이 있을 수 있습니다.
88

@@ -48,8 +48,6 @@
4848

4949
기본적인 아이디어는 너비 우선 탐색과 동일하며, 너비 우선 탐색과 달리 *우선순위 큐*를 사용합니다.
5050

51-
정점의 개수가 $V$, 간선의 개수가 $E$일 때, 다익스트라 알고리즘의 시간복잡도는 $O(ElgV)$입니다.
52-
5351
<br>
5452

5553
### 작동방식
@@ -64,20 +62,96 @@
6462

6563
구체적으로는 아래의 과정을 거칩니다.
6664

67-
1. 시작점으로부터 각 정점까지의 최단 거리를 저장하는 배열 `dist[]``inf`로 초기화합니다.
68-
1. `dist[src]`의 값을 `0`으로 대입합니다. (시작점)
69-
1. 우선순위 큐에 `(src, 0)`을 삽입합니다.
70-
1. 우선순위 큐가 다 비어질 때까지 다음을 반복합니다.
71-
1. 우선순위 큐에서 현재 정점과 현재 최단 거리 쌍을`(here, cost)` 꺼냅니다.
72-
1. 만약 `dist[here]`가 현재 `cost`보다 작다면 지금 꺼낸 것을 무시합니다.
73-
1. 현재 정점에 인접한 정점들을 모두 검사합니다.
74-
1. 이웃 정점(`there`)까지의 거리를 갱신합니다.
75-
1. 그 거리가 `dist[there]`에 저장된 값보다 짧다면 우선순위 큐에 해당 정점을 삽입합니다.
76-
1. 위 과정을 마치면 `dist[]`에는 최단 거리가 모두 저장됩니다.
65+
![다익스트라 0단계](imgs/4.png)
66+
67+
| s | a | b | c | d | e |
68+
| ----- | --- | --- | --- | --- | --- |
69+
| **0** | INF | INF | INF | INF | INF |
70+
71+
![다익스트라 1단계](imgs/5.png)
72+
73+
| s | a | b | c | d | e |
74+
| --- | ----- | ----- | --- | --- | ------ |
75+
| 0 | **7** | **9** | INF | INF | **14** |
76+
77+
![다익스트라 2단계](imgs/6.png)
78+
79+
| s | a | b | c | d | e |
80+
| --- | --- | ----- | ------ | --- | --- |
81+
| 0 | 7 | **9** | **22** | INF | 14 |
82+
83+
![다익스타라 3단계](imgs/7.png)
84+
85+
| s | a | b | c | d | e |
86+
| --- | --- | --- | ------ | --- | ------ |
87+
| 0 | 7 | 9 | **20** | INF | **11** |
88+
89+
![다익스트라 4단계](imgs/8.png)
90+
91+
| s | a | b | c | d | e |
92+
| --- | --- | --- | --- | ------ | --- |
93+
| 0 | 7 | 9 | 20 | **20** | 11 |
94+
95+
![다익스트라 5단계](imgs/9.png)
96+
97+
| s | a | b | c | d | e |
98+
| --- | --- | --- | --- | --- | --- |
99+
| 0 | 7 | 9 | 20 | 20 | 11 |
100+
101+
![다익스트라 6단계](imgs/10.png)
102+
103+
| s | a | b | c | d | e |
104+
| --- | --- | --- | --- | --- | --- |
105+
| 0 | 7 | 9 | 20 | 20 | 11 |
106+
107+
이러한 과정을 코드로 작성하면 아래와 같습니다.
108+
109+
```cpp
110+
#define MAX_V 100
111+
#define INF 987654321
112+
113+
#include <vector>
114+
#include <queue>
115+
116+
using namespace std;
117+
118+
int V;
119+
vector<pair<int, int> > adj[MAX_V];
120+
121+
vector<int> dijkstra(int src) {
122+
vector<int> dist(V, INF);
123+
dist[src] = 0;
124+
125+
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int,int> > > pq;
126+
pq.push(make_pair(0, src));
127+
128+
while (!pq.empty()) {
129+
int cost = pq.top().first;
130+
int here = pq.top().second;
131+
pq.pop();
77132

78-
[이러한 과정을 잘 보여주는 그림을 봅시다.](https://m.blog.naver.com/kks227/220796029558?view=img_1)
133+
if (dist[here] < cost) continue;
79134

80-
[코드는 이렇게 작성됩니다.](dijkstra.cc)
135+
for (const auto& [there, length] : adj[here]) {
136+
int nextDist = cost + length;
137+
138+
if (nextDist < dist[there]) {
139+
dist[there] = nextDist;
140+
pq.push(make_pair(nextDist, there));
141+
}
142+
}
143+
}
144+
return dist;
145+
}
146+
```
147+
148+
### 시간복잡도
149+
150+
정점의 개수가 $V$, 간선의 개수가 $E$일 때, 다익스트라 알고리즘의 시간복잡도는 $O(ElgV)$입니다.
151+
152+
모든 간선을 한 번씩만 검사하며, 모든 정점이 한 번 이상 우선순위 큐에 들어가기 때문입니다.
153+
154+
<br>
81155
82156
## 벨만-포드
83157
@@ -123,9 +197,47 @@ $(a, b) \rightarrow (b, c) \rightarrow (c, a)$ 의 사이클을 돌 때마다
123197
124198
결론적으로, 벨만 포드 알고리즘의 시간 복잡도는 $O(VE)$입니다.
125199
200+
코드는 아래와 같이 작성됩니다.
201+
126202
<br>
127203
128-
[코드는 이렇게 작성됩니다.](bellmanFord.cc)
204+
```cpp
205+
#define MAX_V 100
206+
#define INF 987654321
207+
208+
#include <utility>
209+
#include <vector>
210+
211+
using namespace std;
212+
213+
int V;
214+
vector<pair<int, int> > adj[MAX_V];
215+
216+
vector<int> bellmanFord(int src) {
217+
vector<int> upper(V, INF);
218+
upper[src] = 0;
219+
220+
bool updated;
221+
for (int iter = 0; iter < V; ++iter) {
222+
updated = false;
223+
224+
for (int here = 0; here < V; ++here) {
225+
for (const auto& [there, cost] : adj[here]) {
226+
if (upper[here] != INF && upper[there] > upper[here] + cost) {
227+
upper[there] = upper[here] + cost;
228+
updated = true;
229+
}
230+
}
231+
}
232+
233+
if (!updated) break;
234+
}
235+
236+
if (updated) upper.clear();
237+
238+
return upper;
239+
}
240+
```
129241

130242
<br>
131243

@@ -176,7 +288,28 @@ $(a, b) \rightarrow (b, c) \rightarrow (c, a)$ 의 사이클을 돌 때마다
176288

177289
<br>
178290

179-
[코드는 이렇게 작성됩니다.](floyd.cc)
291+
코드는 아래와 같이 작성됩니다.
292+
293+
```cpp
294+
#define MAX_V 100
295+
#define INF 987654321
296+
297+
#include <vector>
298+
299+
using namespace std;
300+
301+
int V;
302+
int adj[MAX_V][MAX_V];
303+
304+
void floyd() {
305+
for (int i = 0; i < V; ++i) adj[i][i] = 0;
306+
307+
for (int k = 0; k < V; ++k)
308+
for (int i = 0; i < V; ++i)
309+
for (int j = 0; j < V; ++j)
310+
adj[i][j] = min(adj[i][j], adj[i][k] + adj[k][j]);
311+
}
312+
```
180313

181314
<br>
182315

‎day11/bellmanFord.cc

Lines changed: 0 additions & 35 deletions
This file was deleted.

‎day11/dijkstra.cc

Lines changed: 0 additions & 36 deletions
This file was deleted.

‎day11/floyd.cc

Lines changed: 0 additions & 18 deletions
This file was deleted.

‎day11/imgs/10.png

24.5 KB
Loading

‎day11/imgs/4.png

21.7 KB
Loading

‎day11/imgs/5.png

24.5 KB
Loading

‎day11/imgs/6.png

25.6 KB
Loading

‎day11/imgs/7.png

27.4 KB
Loading

‎day11/imgs/8.png

27.5 KB
Loading

‎day11/imgs/9.png

28.2 KB
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.