Опубликован: 08.04.2009 | Доступ: свободный | Студентов: 485 / 0 | Длительность: 17:26:00
Специальности: Программист
Лекция 9:

Разные алгоритмы на графах

< Лекция 8 || Лекция 9: 1234 || Лекция 10 >

9.2. Связные компоненты, поиск в глубину и ширину

Наиболее простой случай задачи о кратчайших путях - если все цены равны 0 или +\infty. Другими словами, мы интересуемся возможностью попасть из i в j, но за ценой не постоим. В других терминах: мы имеем ориентированный граф (картинку из точек, некоторые из которых соединены стрелками) и нас интересуют вершины, доступные из данной.

Для этого случая задачи о кратчайших путях приведенные в предыдущем разделе алгоритмы - не наилучшие. В самом деле, более быстрая рекурсивная программа решения этой задачи приведена в "лекции 7" , а нерекурсивная - в "лекции 6" . Сейчас нас интересует такая задача: не просто перечислить все вершины, доступные из данной, но перечислить их в определенном порядке. Два популярных случая - поиск в ширину и в глубину.

Поиск в ширину.

Надо перечислить все вершины ориентированного графа, доступные из данной, в порядке увеличения длины пути от нее. (Тем самым мы решим задачу о кратчайших путях, когда цены ребер равны 1 или +\infty.)

9.2.1. Придумать алгоритм решения этой задачи с числом действий не более C\cdot{} (число ребер, выходящих из интересующих нас вершин).

Решение. Эта задача рассматривалась в "лекции 6" , задача 6.3.9. Здесь мы приведем подробное решение. Пусть num[i] - количество ребер, выходящих из i, {out[i][1]},\ldots,{out[i][num[i]]} - вершины, куда ведут ребра. Вот программа, приведенная ранее:

procedure Доступные (i: integer);
|   {напечатать все вершины, доступные из i, включая i}
| var  X: подмножество 1..n;
|      P: подмножество 1..n;
|      q, v, w: 1..n;
|      k: integer;
begin
| ...сделать X, P пустыми;
| writeln (i);
| ...добавить i к X, P;
| {(1) P = множество напечатанных вершин; P содержит i;
|  (2) напечатаны только доступные из i вершины;
|  (3) X - подмножество P;
|  (4) все напечатанные вершины, из которых выходит
|      ребро в ненапечатанную вершину, принадлежат X}
| while X непусто do begin
| | ...взять какой-нибудь элемент X в v;
| | for k := 1 to num [v] do begin
| | | w := out [v][k];
| | | if w не принадлежит P then begin
| | | | writeln (w);
| | | | добавить w в P;
| | | | добавить w в X;
| | | end;
| | end;
| end;
end;

Тогда нам было безразлично, какой именно элемент множества X выбирается. Если мы будем считать X очередью (первым пришел - первым ушел), то эта программа напечатает все вершины, доступные из i, в порядке возрастания их расстояния от i (числа ребер на кратчайшем пути из i ). Докажем это.

Обозначим через V(k) множество всех вершин, расстояние которых от i (в описанном смысле) равно k. Имеет место такое соотношение:

V(k+1) = \text{(концы ребер с началами в V(k))}
 \setminus (V(0)
 \cup \ldots
 \cup V(k))
Докажем, что для любого k=0,1,2\ldots в ходе работы программы будет такой момент (после очередной итерации цикла while ), когда
\begin{quote}
     в очереди стоят все элементы V(k) и только они; \\
     напечатаны все элементы V(0),\ldots,V(k).
\end{quote}
(Для k=0 - это состояние перед циклом.) Рассуждая по индукции, предположим, что в очереди скопились все элементы V(k). Они будут просматриваться в цикле, пока не кончатся (поскольку новые элементы добавляются в конец, они не перемешаются со старыми). Концы ведущих из них ребер, если они уже не напечатаны, печатаются и ставятся в очередь - то есть все как в записанном выше соотношении для V(k+1). Так что когда все старые элементы кончатся, в очереди будут стоять все элементы V(k+1).

< Лекция 8 || Лекция 9: 1234 || Лекция 10 >