Алгоритм Флойда: различия между версиями

Материал из Олимпиадное программирование в УлГТУ
Перейти к навигации Перейти к поиску
Нет описания правки
Нет описания правки
Строка 8: Строка 8:
* Шаг 0. Теперь разрешаем путям проходить через вершину 0. Обновляем dist: dist[a][b] = min(dist[a][b], dist[a][0] + dist[0][b]);
* Шаг 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]);
* Шаг 1. Теперь разрешаем путям проходить через вершину 1. Обновляем dist: dist[a][b] = min(dist[a][b], dist[a][1] + dist[1][b]);
* Повторяем до шага n - 1.
* Повторяем до шага vertexCount - 1.


vector<vector<int>> g(n, vector<int>(n));
vector<vector<int>> dist(n, vector<int>(n));
  const int INF = 1e9;
  const int INF = 1e9;
vector<vector<int>> dist(vertexCount, vector<int>(vertexCount, INF));
   
   
// считаем, что петель и кратных рёбер нет, граф задан матрицей смежности g, g[a][b] == 0 --- признак отсутствия ребра
  for (int v = 0; v < vertexCount; v++)
  for (int a = 0; a < n; a++) {
    dist[v][v] = 0;
    for (int b = 0; b < n; b++) {
        if (a == b)
for (int i = 0; i < edgeCount; i++) {
            dist[a][b] = 0;
    int a, b, w;
        else
    cin >> a >> b >> w;
            dist[a][b] = (g[a][b] ? g[a][b] : INF);
    dist[a][b] = min(dist[a][b], w);
    }
  }
  }
   
   
  for (int v = 0; v < n; v++) {
  for (int v = 0; v < vertexCount; v++) {
     for (int a = 0; a < n; a++) {
     for (int a = 0; a < vertexCount; a++) {
         for (int b = 0; b < n; b++) {
         for (int b = 0; b < vertexCount; b++) {
             if (dist[a][v] == INF || dist[v][b] == INF)
             if (dist[a][v] == INF || dist[v][b] == INF)
                 continue;
                 continue;
             dist[a][b] = min(dist[a][b], dist[a][k] + dist[k][b]);
             dist[a][b] = min(dist[a][b], dist[a][k] + dist[k][b]);
             dist[a][b] = min(dist[a][b], -INF);
             dist[a][b] = max(dist[a][b], -INF);
         }
         }
     }
     }

Версия от 03:07, 26 декабря 2021

Ищем расстояния во взвешенном графе от каждой вершины до всех остальных. Веса могут быть любыми.

Идея алгоритма:

  • Инициализация. Пусть 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]);
  • Повторяем до шага vertexCount - 1.
const int INF = 1e9;
vector<vector<int>> dist(vertexCount, vector<int>(vertexCount, INF));

for (int v = 0; v < vertexCount; v++)
    dist[v][v] = 0;

for (int i = 0; i < edgeCount; i++) {
    int a, b, w;
    cin >> a >> b >> w;
    dist[a][b] = min(dist[a][b], w);
}

for (int v = 0; v < vertexCount; v++) {
    for (int a = 0; a < vertexCount; a++) {
        for (int b = 0; b < vertexCount; 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] = max(dist[a][b], -INF);
        }
    }
}

На что нужно обратить внимание:

  • При инициализации матрицы на главной диагонали должны быть нули (если нет петель отрицательного веса), а там, где рёбер нет — бесконечности;
  • При наличии отрицательных рёбер следует избегать присваиваний вида (INF - 1). Для этого, если хотя бы один из фрагментов пути равен INF, нужно делать continue;
  • При наличии отрицательных циклов расстояния могут очень быстро уменьшаться и приводить к отрицательным переполнениям. Поэтому нужно ограничивать отрицательные числа снизу.

Ссылки на задачи

Ссылки