Наиболее просто найти кратчайший путь между каждой из пар вершин можно с помощью алгоритма Флойда. Пусть в элементе матрицы A[i, j] хранится длина пути из вершины i в вершину j. Если же длины пути из вершины i в вершину k и пути из вершины k в вершину j таковы, что их сумма меньше, чем значение данного элемента матрицы, то его следует переопределить. Для реализации алгоритма массив A первоначально следует заполнить элементами матрицы весов, обозначая отсутствие ребра между двумя вершинами “бесконечностью” — числом, заведомо превосходящим длину любого пути в рассматриваемом графе, но меньшим, чем максимальное значение используемого типа данных, чтобы было возможно выполнять с ним арифметические операции.
Const nmax=25;
Var a :array[1..nmax,1..nmax] of real;
i, j, k, n: integer;
f, f1: text;
Begin
Assign (f, '1.txt'); reset(f);
Readln (f, n);
For i:=1 to n do Begin
For j:=1 to n do Read(f, a[i,j]);
Readln (f);
End;
For k := 1 to n do
For i := 1 to n do
For j := 1 to n do
If a [i, j]>a[i, k]+a[k, j] then a[i, j]:= a[i, k]+a[k, j];
Assign (f1, '2.txt'); Rewrite (f1);
For i:=1 to 5 do Begin
For j:=1 to 5 do Write(f1,a[i,j]:4:0,' ');
Writeln(f1);
End;
Close(f1);
End.
В этом решении в исходной матрице весов будут записаны кратчайшие пути между всеми вершинами.
На соревнованиях в условии задачи вряд ли будет дана матрица весов. Там будет, например, как в задаче «На болоте», она приведена в задачах олимпиад.
Если же нам требуется найти сам кратчайший путь, а не его длину, то при каждом улучшении пути между двумя вершинами мы в соответствующем элементе вспомогательного массива (в программе — w) будем запоминать номер той вершины, через которую кратчайший путь проходит, а затем с помощью рекурсивной процедуры будем его печатать. Идея рекурсии заключается в том, что если мы знаем, что кратчайший путь от вершины i до вершины j проходит через вершину k, то мы можем обратиться к той же самой процедуре с частями пути от i до k и от k до j. Выход из рекурсии, когда на кратчайшем пути между двумя вершинами не окажется промежуточных вершин.
Приведем фрагмент программы, реализующий алгоритм Флойда и печатающий кратчайшие пути между всеми парами вершин графа.
Procedure Way(i,j:integer);
{печатает путь между вершинами i и j}
Begin
If w[i,j]=0 then Write (' ', j)
{печатаем только вершину j, чтобы избежать повторов}
else
Begin
Way (i, w [i, j]); Way (w [i, j], j)
End
End;
Begin
…{заполняем матрицу смежности}
… {реализуем алгоритм Флойда }
For k:=1 to nn do
For i:=1 to nn do
For j:=1 to nn do
If a[i,k]+a[k,j]<a[i,j] then
Begin
a[i,j]:=a[i,k]+a[k,j];
w[i,j]:=k
End;
{выводим кратчайшие пути}
For i:=1 to nn do
For j:=1 to nn do Begin
Write(i);
If i<>j then Way(i,j);
Writeln
End
End.
Алгоритм Флойда прост и хорошо запоминается. Но упростить его для определения длины кратчайшего пути между двумя конкретными вершинами невозможно. Для решения такой задачи используйте алгоритм Дейкстры (п. 13.1.3).