На этом шаге мы рассмотрим алгоритм нахождения кратчайших путей между вершинами графа.
Алгоритм Уоршалла может быть модифицирован с целью получения матрицы, содержащей длины кратчайших путей между вершинами [1, с.441].
Идея этого алгоритма следующая [2,с.131]. Обозначим через d(m)ij длину кратчайшего из путей из vi в vj с промежуточными вершинами в множестве {v1, ..., vm}.
Тогда имеем следующие уравнения, объединенные в систему:
d(0)ij = aij d(m)ij = min(d(m)ij, d(m)im + d(m)mj)
Обоснование второго уравнения достаточно простое. Рассмотрим кратчайший путь из vi в vj c промежуточными вершинами из множества {v1, ..., vm,vm+1}. Если этот путь не содержит vm+1, то деля путь на отрезки от vi до vm+1 и от vm+1 до vj, получаем равенство
d(m+1)ij = d(m)im + d(m)mj).
Вышеприведенные уравнения дают возможность легко вычислить расстояния
d(vi,vj) = d(n)ij, 1 <= i, j <= n.
Для машинной реализации алгоритма предположим, что A - матрица смежности графа. Заменим все нулевые элементы A на "бесконечность" или на некоторое "очень большое число", которое в данной матрице обозначим через B. Требуемая матрица длин минимальных путей формируется следующим алгоритмом, записанным на языке C++.
#include <iostream.h> #define MaxNodes 4 #define B 1000 class Warshall { private: unsigned Adj[MaxNodes][MaxNodes]; //Матрица смежностей. unsigned C[MaxNodes][MaxNodes]; //Матрица достижимости. public: void Vvod(); void MinDlin(); void Vyvod(); }; void Warshall::Vvod() //Ввод матрицы смежностей заданного графа и ее "исправление". { //Ввод матрицы смежностей заданного графа. cout <<"Вводите элементы матрицы смежностей по строкам:\n"; for (int i=0;i<MaxNodes;i++) for (int j=0;j<MaxNodes;j++) { cout <<"Введите Adj["<< (i+1) << "]["<< (j+1) << "]: "; cin >> Adj[i][j]; if (Adj[i][j]==0) C[i][j] = B; else C[i][j] = Adj[i][j]; } } void Warshall::MinDlin() //Вычисление матрицы минимальных длин путей. { for (int k=0;k<MaxNodes;k++) for (int i=0;i<MaxNodes;i++) for (int j=0;j<MaxNodes;j++) if ( C[i][j]>C[i][k]+C[k][j] ) C[i][j] = C[i][k]+C[k][j]; } void Warshall::Vyvod() //Вывод матрицы минимальных длин путей. { cout << "Матрица минимальных длин путей:\n"; for (int i=0;i<MaxNodes;i++) { for (int j=0;j<MaxNodes;j++) cout << C[i][j] << " "; cout << endl; } } void main() { Warshall A; A.Vvod(); A.MinDlin(); A.Vyvod(); }
Очевидно, что сложность алгоритма есть O(n3). В монографии [2, с.132] отмечено, что "для общего случая (т.е. без предположения о неотрицательности весов или о бесконтурности графа) не известен ни один алгоритм нахождения расстояния между одной фиксированной парой вершин, который был бы значительно эффективнее алгоритма нахождения расстояний между всеми парами вершин."
На следующем шаге мы рассмотрим алгоритм отыскания компонент сильной связности.