Алгоритм Флойда: различия между версиями
Перейти к навигации
Перейти к поиску
Ctrlalt (обсуждение | вклад) (→Ссылки) |
Ctrlalt (обсуждение | вклад) Нет описания правки |
||
Строка 1: | Строка 1: | ||
Ищем расстояния во взвешенном графе от каждой вершины до всех остальных. Веса могут быть любыми. | |||
Идея алгоритма: | |||
* Инициализация. Пусть dist[a][b] — кратчайшее расстояние от a до b, но длиной не более чем одно ребро. Нетрудно понять, что dist — это просто матрица смежности графа (возможно, с небольшими модификациями): | |||
:* Случай простого графа: dist[a][a] = 0, dist[a][b] = весу ребра (a, b); если ребра (a, b) нет, то dist[a][b] = INF; | |||
:* Если есть кратные рёбра, то dist[a][b] = весу минимального ребра между a и b; | |||
:* Если есть петли, то dist[a][a] = min(0, вес минимальной петли из a); | |||
* Шаг 0. Теперь разрешаем путям проходить через вершину 0. Обновляем dist: dist[a][b] = min(dist[a][b], dist[a][0] + dist[0][b]); | |||
* Шаг 1. Теперь разрешаем путям проходить через вершину 1. Обновляем dist: dist[a][b] = min(dist[a][b], dist[a][1] + dist[1][b]); | |||
* Повторяем до шага n - 1. | |||
vector<vector<int>> g(n, vector<int>(n)); | |||
vector<vector<int>> dist(n, vector<int>(n)); | |||
const int INF = 1e9; | |||
for (int | // считаем, что петель и кратных рёбер нет, граф задан матрицей смежности g, g[a][b] == 0 --- признак отсутствия ребра | ||
for (int | for (int a = 0; a < n; a++) { | ||
dist[ | for (int b = 0; b < n; b++) { | ||
if (a == b) | |||
dist[a][b] = 0; | |||
else | |||
dist[a][b] = (g[a][b] ? g[a][b] : INF); | |||
} | |||
} | |||
for (int | for (int v = 0; v < n; v++) { | ||
for (int | for (int a = 0; a < n; a++) { | ||
for (int | for (int b = 0; b < n; b++) { | ||
if (dist[ | if (dist[a][v] == INF || dist[v][b] == INF) | ||
continue; | |||
dist[a][b] = min(dist[a][b], dist[a][k] + dist[k][b]); | |||
dist[a][b] = min(dist[a][b], -INF); | |||
} | |||
} | |||
} | |||
На что нужно обратить внимание: | |||
* При инициализации матрицы на главной диагонали должны быть нули (если нет петель отрицательного веса), а там, где рёбер нет — бесконечности; | |||
* При наличии отрицательных рёбер следует избегать присваиваний вида (INF - 1). Для этого, если хотя бы один из фрагментов пути равен INF, нужно делать continue; | |||
* При наличии отрицательных циклов расстояния могут очень быстро уменьшаться и приводить к отрицательным переполнениям. Поэтому нужно ограничивать отрицательные числа снизу. | |||
== Ссылки на задачи == | == Ссылки на задачи == | ||
Строка 20: | Строка 49: | ||
* [http://e-maxx.ru/algo/floyd_warshall_algorithm e-maxx.ru — Алгоритм Флойда-Уоршелла] | * [http://e-maxx.ru/algo/floyd_warshall_algorithm e-maxx.ru — Алгоритм Флойда-Уоршелла] | ||
* [http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A4%D0%BB%D0%BE%D0%B9%D0%B4%D0%B0 neerc.ifmo.ru/wiki — Алгоритм Флойда] | * [http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A4%D0%BB%D0%BE%D0%B9%D0%B4%D0%B0 neerc.ifmo.ru/wiki — Алгоритм Флойда] | ||
* [http://brestprog. | * [http://brestprog.by/topics/floyd/ brestprog — Алгоритм Флойда-Уоршелла] | ||
* [http://algorithmica.org/tg/shortest-paths algorithmica.org — Кратчайшие пути в графе] | * [http://algorithmica.org/tg/shortest-paths algorithmica.org — Кратчайшие пути в графе] | ||
* [http://brilliant.org/wiki/floyd-warshall-algorithm Brilliant.org — Floyd-Warshall Algorithm] | * [http://brilliant.org/wiki/floyd-warshall-algorithm Brilliant.org — Floyd-Warshall Algorithm] |
Версия от 16:44, 15 февраля 2020
Ищем расстояния во взвешенном графе от каждой вершины до всех остальных. Веса могут быть любыми.
Идея алгоритма:
- Инициализация. Пусть dist[a][b] — кратчайшее расстояние от a до b, но длиной не более чем одно ребро. Нетрудно понять, что dist — это просто матрица смежности графа (возможно, с небольшими модификациями):
- Случай простого графа: dist[a][a] = 0, dist[a][b] = весу ребра (a, b); если ребра (a, b) нет, то dist[a][b] = INF;
- Если есть кратные рёбра, то dist[a][b] = весу минимального ребра между a и b;
- Если есть петли, то dist[a][a] = min(0, вес минимальной петли из a);
- Шаг 0. Теперь разрешаем путям проходить через вершину 0. Обновляем dist: dist[a][b] = min(dist[a][b], dist[a][0] + dist[0][b]);
- Шаг 1. Теперь разрешаем путям проходить через вершину 1. Обновляем dist: dist[a][b] = min(dist[a][b], dist[a][1] + dist[1][b]);
- Повторяем до шага n - 1.
vector<vector<int>> g(n, vector<int>(n)); vector<vector<int>> dist(n, vector<int>(n)); const int INF = 1e9; // считаем, что петель и кратных рёбер нет, граф задан матрицей смежности g, g[a][b] == 0 --- признак отсутствия ребра for (int a = 0; a < n; a++) { for (int b = 0; b < n; b++) { if (a == b) dist[a][b] = 0; else dist[a][b] = (g[a][b] ? g[a][b] : INF); } } for (int v = 0; v < n; v++) { for (int a = 0; a < n; a++) { for (int b = 0; b < n; b++) { if (dist[a][v] == INF || dist[v][b] == INF) continue; dist[a][b] = min(dist[a][b], dist[a][k] + dist[k][b]); dist[a][b] = min(dist[a][b], -INF); } } }
На что нужно обратить внимание:
- При инициализации матрицы на главной диагонали должны быть нули (если нет петель отрицательного веса), а там, где рёбер нет — бесконечности;
- При наличии отрицательных рёбер следует избегать присваиваний вида (INF - 1). Для этого, если хотя бы один из фрагментов пути равен INF, нужно делать continue;
- При наличии отрицательных циклов расстояния могут очень быстро уменьшаться и приводить к отрицательным переполнениям. Поэтому нужно ограничивать отрицательные числа снизу.
Ссылки на задачи
- ACMP #135 — Алгоритм Флойда
- ACMP #136 — Алгоритм Флойда - 2
- ACMP #137 — Существование пути
- ACMP #562 — Слабая K-связность
Ссылки
- e-maxx.ru — Алгоритм Флойда-Уоршелла
- neerc.ifmo.ru/wiki — Алгоритм Флойда
- brestprog — Алгоритм Флойда-Уоршелла
- algorithmica.org — Кратчайшие пути в графе
- Brilliant.org — Floyd-Warshall Algorithm
- informatics.mccme.ru — Курс «Алгоритмы на графах» — часть 5
- CodeLibrary — Floyd–Warshall algorithm
- Algos — Floyd–Warshall algorithm