1. Лекция 9:
Кратчайшие пути в графах
Курносов Михаил Георгиевич
к.т.н. доцент Кафедры вычислительных систем
Сибирский государственный университет
телекоммуникаций и информатики
http://www.mkurnosov.net
2. Контроль
2
1. Какова вычислительная сложность обхода графа в глубину
(DFS), если он представлен матрицей смежности?
2. Какова вычислительная сложность обхода графа в глубину
(DFS), если он представлен списками смежности?
3. Какова вычислительная сложность обхода графа в ширину
(BFS), если он представлен матрицей смежности?
4. Какова вычислительная сложность обхода графа в ширину
(BFS), если он представлен списками смежности?
3. Графы
3
Граф (graph) – это совокупность непустого
множества V вершин и множества E ребер
G = (V, E),
|V| = n, |E| = m,
V = {1, 2, …, n}, E = {(u1, v1), (u2, v2), …, (um, vm)}
4. Поиск кратчайшего пути в графе
4
Имеется взвешенный граф G = (V, E)
Каждому ребру (i, j) ∈ E
назначен вес wij
Заданы начальная вершина s ∈ V
и конечная d ∈ V
Требуется найти
кратчайший путь (shortest path)
из вершины s в вершину d
Длина пути (path length,
path cost, path weight) –
это сумма весов ребер, входящих в него.
s
(source)
d (destination)
5. Поиск кратчайшего пути в графе
5
Длина пути (5, 4, 6, 7) =
4 + 6 + 9 = 19
Длина пути (5, 3, 8, 7) =
3 + 2 + 16 = 21
Длина пути (5, 3, 4, 6, 7) =
3 + 3 + 6 + 9 = 21
Существуют другие пути?
(5, 1, 4, 3, 8, 7)
(5, 2, 3, 8, 7)
…
s
(source)
d (destination)
6. Алгоритм Дейкстры
6
Алгоритм Дейкстры (Dijkstra’s algorithm, 1959) –
алгоритм поиска кратчайшего пути в графе. Применим
только для графов без ребер отрицательного веса.
Эдсгер Дейкстра (Edsger Wybe Dijkstra) – нидерландский
ученый (структурное программирование, язык Алгол,
семафоры)
1. Дейкстра Э. Дисциплина программирования = A discipline of
programming. — 1-е изд. — М.: Мир, 1978. — С. 275.
2. Дал У., Дейкстра Э., Хоор К. Структурное программирование =
Structured Programming. — 1-е изд. — М.: Мир, 1975. — С. 247.
7. Алгоритм Дейкстры (Dijkstra)
7
1
2
5
3
4
100
10
30
50
10
20
60
Пример: найти кратчайший путь из
вершины 1 в вершину 5.
Введем обозначения:
H – множество посещенных вершин
D[i] – текущее известное кратчайшее
расстояние от вершины s до вершины i
prev[i] – номер вершины,
предшествующей i в пути
8. Алгоритм Дейкстры (Dijkstra)
8
1
2
5
3
4
100
10
30
50
10
20
60
1. Устанавливаем расстояние D[i]
от начальной вершины s до всех
остальных в ∞.
2. Полагаем D[s] = 0.
3. Помещаем все вершины
в очередь Q с приоритетом.
Приоритет вершины i это значение D[i].
0 ∞ ∞ ∞ ∞D[i]
9. Алгоритм Дейкстры (Dijkstra)
9
1
2
5
3
4
100
10
30
50
10
20
60
4. Запускаем цикл из n итераций.
1. Извлекаем из очереди Q вершину
с минимальным приоритетом –
текущем расстоянием D[v] до s.
2. Помещаем v во множество H
посещенных вершин.
3. Для каждой вершины u смежной с
вершиной v и не включенной в H
корректируем расстояние D[u]
if D[v] + w(v, u) < D[u] then
D[u] = D[v] + w(v, u)
PQueueDecrease(Q, u, D[u])
prev[u] = v
end if
D[2] = 10
D[4] = 30
D[5] = 100
0 10 ∞ 30 100D[i]
11
10. Алгоритм Дейкстры (Dijkstra)
10
1
2
5
3
4
100
10
30
50
10
20
60
4. Цикл из n итераций.
1. Извлекаем из очереди Q вершину
с минимальным приоритетом –
текущем расстоянием D[v] до s.
2. Помещаем v во множество H
посещенных вершин.
3. Для каждой вершины u смежной с
вершиной v и не включенной в H
корректируем расстояние D[u]
if D[v] + w(v, u) < D[u] then
D[u] = D[v] + w(v, u)
PQueueDecrease(Q, u, D[u])
prev[u] = v
end if
D[3] = 60
0 10 60 30 100D[i]
2
1
2
11. Алгоритм Дейкстры (Dijkstra)
11
1
2
5
3
4
100
10
30
50
10
20
60
4. Цикл из n итераций.
1. Извлекаем из очереди Q вершину
с минимальным приоритетом –
текущем расстоянием D[v] до s.
2. Помещаем v во множество H
посещенных вершин.
3. Для каждой вершины u смежной с
вершиной v и не включенной в H
корректируем расстояние D[u]
if D[v] + w(v, u) < D[u] then
D[u] = D[v] + w(v, u)
PQueueDecrease(Q, u, D[u])
prev[u] = v
end if
D[3] = 50
D[5] = 90
0 10 50 30 90D[i]
4
1
4
2
12. Алгоритм Дейкстры (Dijkstra)
12
1
2
5
3
4
100
10
30
50
10
20
60
4. Цикл из n итераций.
1. Извлекаем из очереди Q вершину
с минимальным приоритетом –
текущем расстоянием D[v] до s.
2. Помещаем v во множество H
посещенных вершин.
3. Для каждой вершины u смежной с
вершиной v и не включенной в H
корректируем расстояние D[u]
if D[v] + w(v, u) < D[u] then
D[u] = D[v] + w(v, u)
PQueueDecrease(Q, u, D[u])
prev[u] = v
end if
D[5] = 60
0 10 50 30 60D[i]
3
1
3
2
4
13. Алгоритм Дейкстры (Dijkstra)
13
В массиве D длины кратчайших путей
из вершины 1 во все остальные
Кротчайший путь из вершины
1 в вершину 5: (1, 4, 3, 5), длина пути: 60
Как восстановить путь?
0 10 50 30 60D[i]
3
1
2
3
4
1
2
5
3
4
100
10
30
50
10
20
60
-1 1 4 1 3prev[i]
14. function Dijkstra(G, s, d)
/* Input: G = (V, E), s, d */
/* Output: path, pathlen */
for each i in V {s} do
d[i] = Infinity
prev[i] = -1
PQueueInsert(Q, i, d[i])
end for
d[s] = 0
prev[s] = -1
PQueueInsert(Q, s, d[s])
Алгоритм Дейкстры (Dijkstra)
14
15. Алгоритм Дейкстры (Dijkstra)
15
for i = 0 to n – 1 do
v = PQueueRemoveMin(Q)
H = H + {v}
for each u in Adj(v) H do
if d[v] + w(v, u) < d[u] then
d[u] = d[v] + w(v, u)
PQueueDecrease(Q, u, d[u])
prev[u] = v
end if
end for
end for
16. /* Сохранение пути из s в d */
i = d
pathlen = 1
while i != s do
pathlen = pathlen + 1
i = prev[i]
end while
j = 0
i = d
while i != s do
path[pathlen – j] = i
i = prev[i]
j = j + 1
end while
end function
Алгоритм Дейкстры (Dijkstra)
16
17. Вычислительная сложность алгоритм Дейкстры
17
Вычислительная сложность алгоритма зависит от двух
факторов:
1) от выбора структуры данных для хранения графа
(матрица смежности, списки смежных вершин)
2) от способа поиска вершины с минимальным
расстоянием D[i] (очередь с приоритетом, линейный
поиск)
18. O(n(logn))
Алгоритм Дейкстры (Dijkstra)
18
function Dijkstra(G, s, d)
/* Input: G = (V, E), s, d */
/* Output: path, pathlen */
for each i in V {s} do
d[i] = Infinity
prev[i] = -1
PQueueInsert(Q, i, d[i])
end for
d[s] = 0
prev[s] = -1
PQueueInsert(Q, s, d[s])
19. Алгоритм Дейкстры (Dijkstra)
19
for i = 0 to n – 1 do
v = PQueueRemoveMin(Q)
H = H + {v}
for each u in Adj(v) H do
if d[v] + w(v, u) < d[u] then
d[u] = d[v] + w(v, u)
PQueueDecrease(Q, u, d[u])
prev[u] = v
end if
end for
end for
O(nlogn + mlogn)
20. Алгоритм Дейкстры (Dijkstra)
20
/* Сохранение пути из s в d */
pathlen = 1
while i != s do
pathlen = pathlen + 1
i = prev[i]
end while
j = 0
i = d
while i != s do
path[pathlen – j] = i
i = prev[i]
j = j + 1
end while
end function
O(n)
O(n)
21. int search_spath_dijkstra(struct graph *g,
int s, int d, int *path, int *pathlen)
{
int *dist, *prev, *color;
int n, i, j, v, distance, dnew;
n = g->nvertices;
dist = malloc(sizeof(*dist) * n);
prev = malloc(sizeof(*prev) * n);
color = malloc(sizeof(*color) * n);
for (i = 0; i < n; i++) {
dist[i] = INT_MAX;
prev[i] = -1;
color[i] = 0;
}
dist[s - 1] = 0;
Алгоритм Дейкстры (Dijkstra)
21
22. Алгоритм Дейкстры (Dijkstra)
22
for (i = 0; i < n; i++) {
/* Find v with minimal dist[j] */
v = -1;
for (j = 0; j < n; j++) {
if (color[j] == 0 && (v == -1 ||
dist[j] < dist[v]))
{
v = j;
}
}
color[v] = 1;
23. for (j = 0; j < n; j++) {
if (color[j] > 0 ||
graph_get_edge(g, v + 1, j + 1) == 0)
{
continue;
}
dnew = dist[v] +
graph_get_edge(g, v + 1, j + 1);
if (dnew < dist[j]) {
dist[j] = dnew;
prev[j] = v;
}
}
} /* end for i */
Алгоритм Дейкстры (Dijkstra)
23
24. /* Number of vertices in shortest path */
j = 1;
for (i = d - 1; i != s - 1; i = prev[i])
j++;
*pathlen = j;
/* Copy shortest path */
for (i = d - 1; i != s - 1; i = prev[i])
path[--j] = i + 1;
path[0] = s;
distance = dist[d - 1];
free(color);
free(prev);
free(dist);
return distance;
}
Алгоритм Дейкстры (Dijkstra)
24
26. path = malloc(sizeof(*path) * 5);
d = search_spath_dijkstra(g, 1, 5,
path, &pathlen);
printf("Shortest path %d:n", d);
for (i = 0; i < pathlen; i++) {
printf("%dn", path[i]);
}
free(path);
graph_free(g);
return 0;
}
Алгоритм Дейкстры (Dijkstra)
26
27. Задание
27
1. Оценить трудоемкость по памяти алгоритма Дейкстры
в следующих случаях:
o при использовании матрицы смежности
и двоичной кучи;
o при использовании списков смежности
и двоичной кучи
2. Алгоритм Беллмана — Форда
3. Алгоритм Флойда — Уоршелла