Лекция 9: Графы. Кратчайшие пути в графах
TRANSCRIPT
Лекция 9:
Кратчайшие пути в графах
Курносов Михаил Георгиевич
к.т.н. доцент Кафедры вычислительных систем
Сибирский государственный университет
телекоммуникаций и информатики
http://www.mkurnosov.net
Контроль
2
1. Какова вычислительная сложность обхода графа в глубину
(DFS), если он представлен матрицей смежности?
2. Какова вычислительная сложность обхода графа в глубину
(DFS), если он представлен списками смежности?
3. Какова вычислительная сложность обхода графа в ширину
(BFS), если он представлен матрицей смежности?
4. Какова вычислительная сложность обхода графа в ширину
(BFS), если он представлен списками смежности?
Графы
3
� Граф (graph) – это совокупность непустого
множества V вершин и множества E ребер
G = (V, E),
|V| = n, |E| = m,
V = {1, 2, …, n}, E = {(u1, v1), (u2, v2), …, (um, vm)}
Поиск кратчайшего пути в графе
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, 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
� Алгоритм Дейкстры (Dijkstra’s algorithm, 1959) –
алгоритм поиска кратчайшего пути в графе. Применим
только для графов без ребер отрицательного веса.
� Эдсгер Дейкстра (Edsger Wybe Dijkstra) – нидерландский
ученый (структурное программирование, язык Алгол,
семафоры)
1. Дейкстра Э. Дисциплина программирования = A discipline of
programming. — 1-е изд. — М.: Мир, 1978. — С. 275.
2. Дал У., Дейкстра Э., Хоор К. Структурное программирование =
Structured Programming. — 1-е изд. — М.: Мир, 1975. — С. 247.
Алгоритм Дейкстры (Dijkstra)
7
1
2
5
3
4
100
10
30
5010
20
60
Пример: найти кратчайший путь из
вершины 1 в вершину 5.
Введем обозначения:
� H – множество посещенных вершин
� D[i] – текущее известное кратчайшее
расстояние от вершины s до вершины i
� prev[i] – номер вершины,
предшествующей i в пути
Алгоритм Дейкстры (Dijkstra)
8
1
2
5
3
4
100
10
30
5010
20
60
1. Устанавливаем расстояние D[i]
от начальной вершины s до всех
остальных в ∞.
2. Полагаем D[s] = 0.
3. Помещаем все вершины
в очередь Q с приоритетом.
Приоритет вершины i это значение D[i].
0 ∞ ∞ ∞ ∞D[i]
Алгоритм Дейкстры (Dijkstra)
9
1
2
5
3
4
100
10
30
5010
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
Алгоритм Дейкстры (Dijkstra)
10
1
2
5
3
4
100
10
30
5010
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
Алгоритм Дейкстры (Dijkstra)
11
1
2
5
3
4
100
10
30
5010
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
Алгоритм Дейкстры (Dijkstra)
12
1
2
5
3
4
100
10
30
5010
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
Алгоритм Дейкстры (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
5010
20
60
-1 1 4 1 3prev[i]
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
Алгоритм Дейкстры (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
/* Сохранение пути из 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
� Вычислительная сложность алгоритма зависит от двух
факторов:
1) от выбора структуры данных для хранения графа
(матрица смежности, списки смежных вершин)
2) от способа поиска вершины с минимальным
расстоянием D[i] (очередь с приоритетом, линейный
поиск)
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])
Алгоритм Дейкстры (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)
Алгоритм Дейкстры (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)
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
Алгоритм Дейкстры (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;
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
/* 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
Алгоритм Дейкстры (Dijkstra)
25
int main()
{
struct graph *g;
int *path, pathlen;
int i, d;
g = graph_create(5);
graph_set_edge(g, 1, 2, 10);
graph_set_edge(g, 1, 4, 30);
graph_set_edge(g, 1, 5, 100);
graph_set_edge(g, 2, 3, 50);
graph_set_edge(g, 3, 4, 20);
graph_set_edge(g, 3, 5, 10);
graph_set_edge(g, 4, 5, 60);
1
2
5
3
4
100
10
30
5010
20
60
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("%d\n", path[i]);
}
free(path);
graph_free(g);
return 0;
}
Алгоритм Дейкстры (Dijkstra)
26
Задание
27
1. Оценить трудоемкость по памяти алгоритма Дейкстры
в следующих случаях:
o при использовании матрицы смежности
и двоичной кучи;
o при использовании списков смежности
и двоичной кучи
2. Алгоритм Беллмана — Форда
3. Алгоритм Флойда — Уоршелла