II.
Если на шаге (6) была достигнyта веpшина t, то восстановить кpатчайший пyть можно следyющим обpазом: сpеди соседей веpшины t найдем любую веpшину с волновой меткой T(t)-1, сpеди соседей последней - веpшину с меткой T(t)-2, и т.д., пока не достигнем s. Найденная последовательность вершин определяет один из кpатчайших пyтей из s в t. Hа пpактике выгодно сохpанять на шаге (4) инфоpмацию о том, из какой веpшины "волна" пpишла в веpшинy uj - тогда восстановление пyти осyществляется быстpее.
Разметка графа после выполнения волнового алгоритма.
Доказательство корректности волнового алгоритма
Под корректностью алгоритма здесь понимается, что:
А. алгоритм завершает работу за конечное время;
B. если решение существует, то алгоритм находит правильное решение.
Будем называть итерацией волнового алгоритма очередное выполнение шагов (4)-(7) алгоритма.
A.
Волновой алгоритм завершает работу за конечное число итераций - это следует из конечности графа, а также из того, что на каждой итерации либо происходит уменьшение количества вершин графа, волновая метка которых равна "-1" (на шаге 4), либо завершение работы алгоритма (на шаге 5).
B.
1. Докажем по индукции, что (*) к началу выполнения шага (4) алгоритма при заданном значении T волновые метки всех вершин vi, таких, что расстояние (т.е. количество ребер в кратчайшем пути) между s и vi равно T, также равны T ((d(s,vi)=T) => (T(vi)=T)), и, кроме того, все эти вершины находятся в списке OldFront. Базис индукции: при T=0 утверждение (*) выполняется (единственной вершиной, находящейся на расстоянии 0 от s, является сама вершина s; на шаге (3) она получит волновую метку 0 и будет занесена в OldFront); при T=1 утверждение (*) также выполняется (т.к. при T=0 все вершины, инцидентные s, получат волновую метку 1 и попадут сначала в NewFront, а затем, на шаге (7) алгоритма, в OldFront). Допустим, что (**) утверждение (*) выполняется для всех T<T0 (T0>1). Рассмотрим все вершины uj, находящиеся на расстоянии T0 от s: d(s,uj)=T0. Запишем кратчайший путь из s в uj в виде L=(s(s,w1)w1...(wk,uj)uj), где k=T0-1. Путь L'=(s(s,w1)w1...(wk-1,wk)wk) является кратчайшим путем из s в wk (в противном случае L не являлся бы кратчайшим путем из s в uj), его длина T'=T0-1<T0, поэтому в силу (**) к началу выполнения шага (4) алгоритма при T=T', во-первых, T(wk)=T', и, во-вторых, wk находится в OldFront. Вершины wk и uj являются смежными, поэтому на шаге (4) вершина uj получит волновую метку T'+1=T0 и попадет в NewFront. На шаге (7) значение T будет увеличено на единицу, а NewFront скопирован в OldFront, следовательно, утверждение (*) будет выполняться при T=T0.
2. Поскольку при работе алгоритма T "пробегает" все целые значения, начиная с 0 и кончая некоторым целым числом, большим либо равным 0, из 1 следует, что если волновая метка вершины не равна -1, то она равна расстоянию между s и этой вершиной ((T(vi)=a, a =/= -1) => (d(s,vi)=a)).
3. Докажем, что (*) если решение существует, т.е. существует кратчайший путь из s в t длины d(s,t), то выполнение шага (4) при T'=d(s,t)-1 будет иметь место. Единственной возможностью для завершения работы алгоритма при некотором T''<T' является выход на шаге (5), но такой выход возможен тогда и только тогда, когда (**) ни одна из вершин, находящихся на расстоянии T'' от s, не имеет инцидентных вершин, находящихся на расстоянии, большем T'', от s. Действительно, выход на шаге (5) происходит, если и только если список NewFront пуст, а это возможно, если и только если на данной итерации все вершины, инцидентные вершинам из OldFront, имеют волновые метки, не равные -1. Волновые метки этих вершин не могут быть больше T'' (т.к. отличные от -1 значения были присвоены им на итерациях алгоритма при T<T''), следовательно, волновые метки находятся в диапазоне [0..T'']. В силу 2 волновые метки вершин, не равные -1, равны расстояниям между s и этими вершинами, что и доказывает (**). Из (**) cледует, что путей между s и вершинами, находящимися на расстоянии T>T'', в том числе между s и t, не существует. Значит, выход на шаге (5) при T''<T' не может произойти и утверждение (*) верно.
4. Из 1-3 следует: (*) волновые метки вершин vi, находящихся на расстоянии, меньшем d(s,t), от s, равны этому расстоянию ((d(vi,s)<d(s,t)) => (T(vi)=d(vi,s))); (**) на некоторой итерации вершина t получит волновую метку d(s,t) и попадет в NewFront, следовательно, алгоритм завершится на шаге (6) той же итерации. Корректность используемого способа восстановления кратчайшего пути по волновым меткам вершин следует из (*).
Существуют модификации приведенного здесь алгоритма, позволяющие находить:
- кратчайшие пути между s и всеми другими вершинами графа;
- все кратчайшие пути (либо не более чем заданное количество путей) между s и t.