
сиаод / Otvety_Saod
.pdf7.IF НОВЫЙ[u] THEN BEGIN
8.ОЧЕРЕДЬ <= u; НОВЫЙ[u] := false
9.END
10.END
11.END
Как и для поиска в глубину, можно легко показать, что вызов процедуры WS(v) приводит к посещению всех вершин компоненты связности графа, содержащей вершину v, причем каждая вершина просматривается ровно один раз. Вычислительная сложность алгоритма также имеет порядок m+n, т.к. каждая вершина помещается в очередь и удаляется из очереди в точности один раз, а число итераций цикла 6, очевидно, будет иметь порядок числа ребер графа.
Этот метод основан на замене стека очередью. В этом случае, чем раньше посещается вершина (помещается в очередь), тем раньше она используется (удаляется из очереди). Использование вершины происходит с помощью просмотра сразу всех еще непросмотренных соседей этой вершины.
1PROCEDURE WS(v);
{поиск в ширину в графе с началом в вершине v; переменные НОВЫЙ, СПИСОК - глобальные}
2BEGIN
3ОЧЕРЕДЬ := 0; ОЧЕРЕДЬ <= v; НОВЫЙу := false;
4WHILE ОЧЕРЕДЬ :Ф 0 DO begin
5Р<= ОЧЕРЕДЬ; посетить р;
6FOR tСПИСОКр DO
7IF НОВЫЙt THEN BEGIN
8 |
ОЧЕРЕДЬ <= t; НОВЫЙt := false |
9 |
END |
10END
11END
Вызов процедуры WS(v) приводит к посещению всех вершин компоненты связности графа, содержащей вершину v, причем каждая вершина просматривается ровно один раз. Вычислительная сложность алгоритма также имеет порядок m+n, т.к. каждая вершина помещается в очередь и удаляется из очереди в точности один раз, а число итераций цикла 6, очевидно, будет иметь порядок числа ребер графа.
Поиск в графе в ширину может быть использован для нахождения пути между фиксированными вершинами v и t. Для этого достаточно начать поиск в графе с вершины v и вести его до вершины t.
Модернизированный алгоритм поиска в ширину. Модифицируем процедуру WS, заменяя строки 7-9 на
IF НОВЫЙt THEN BEGIN
ОЧЕРЕДЬ <= t; НОВЫЙt := false; ПРЕДЫДУЩИЙ[t] :=Р
END
По окончанию работы модифицированной процедуры таблица ПРЕДЫДУЩИЙ содержит для каждой вершины и вершину ПРЕДЫДУЩИЙ[t], из которой мы попали в t.
Процедуру WS можно использовать без всяких модификаций и тогда, когда списки инцидентности СПИСОК[у], veV, определяют некоторый ориентированный граф. Очевидно, что тогда посещаются только те вершины, до которых существует путь от вершины, с которой мы начали поиск.
52. Топологическая сортировка. Алгоритм топологической сортировки.
Топологическая сортировка ориентированного ациклического графа G=(V,E) представляет собой такое линейное упорядочение всех его вершин, что если граф G содержит ребро (u,v), то u при таком упорядочении располагается до v (если граф не является ацикличным, такая сортировка невозможна). Топологическую сортировку графа можно рассматривать как такое
упорядочение его вершин вдоль горизонтальной линии, что все ребра направлены слева направо.
Мы можем выполнить топологическую сортировку за время θ(V+E), поскольку поиск в глубину выполняется именно за это время, а вставка каждой из |V| вершин в начало связного списка занимает время О.
Алгоритм TopologSort(G)
1.for each v V do
2.num [v] ←0
3.lable [v] ←0
4.end for
5.j←|V|+1
6.i←0
7.for each v V do
8.if num [v]=0 then TOPSORT(V)
9.end for TOPSORT(V)
1.i←i+1
2.num [i] ←i
3.for each w V, смежные с v do
4.if num[w]=0 then TOPSORT(W)
5.else if lable [w] to then
6.printf “граф содержит цикл”
7.end if
8.end if
53. Двусвязность. Алгоритм определения двусвязности графа.
Если граф не одержит точек разделения, то он наз-ся двусвязным или неразделимым. Максимальный подграф наз-ся двусвязной компонентой или блоком. Для определения точек сочленения – последовательно убирать точки и анализировать, распадается ли граф на несвязные компоненты.
Алгоритм BICONNECTIVITY(G)
1.num ←0, stack ←Ø
2.for each v V do Num[v] ←0, L[v] ←0
3.for each v V do
4.if Num[v]=0 then
Block(v,a)
1.num ← num+1
2.Num[v] ←num
3.L[v] ←num
4.for each w V, смежные c V do
5.if Num[w]=0 then
6.stack ←(v,w)
7.Block(w,v)
8.L[v] ←Min(L[v],L[w])
9.if L[w]≥Num[v] then
10.repeat
11.(v1, w1) ←stack
12.printf “(v1,w2)”
13.until(v1, w1) = (v,w)
14.else if(Num[w] ←Num[v]) and (w≠u) then
15.stack
16.L[v] ←Min(L[v], Num[v])
17.end if
18.end if
19.end if
20.end for

Метка вершины сочленения получает минимальный номер из всех вершин блока.
Вычислительная сложность: О(n+m)
54. Сильно связные компоненты. Алгоритм.
Слабо связные компоненты ориентированного графа легко получить игнорируя положения ребер и алгоритм нахождения связных компонент неориентированного графа.
Алгоритм:
10.Выполнить обход в глубину с сохранением номера окончания обработки узла.
11.Заменить все ребра ориентированного графа на противоположные.
12.Выполнить обход в глубину модиф. графа, при этом вершины рассматриваются в порядке убывания номера окончания обработки узла.
13.Деревья леса поиска в глубину получающиеся на предыдущем этапе представляют собой сильно связные компоненты графа.
Используется 2 раза обход в глубину.
Вычислительная сложность: О(n+m) – граф в виде списка смежности, О(n2) – граф в виде матрицы смежности.
55. Эйлеровы пути и циклы. Алгоритм нахождения эйлерова цикла в графе.
Эйлеров путь в графе – произвольный путь, проходящий через каждое ребро графа ровно один раз, т.е. такой путь v1,..., vm 1 , что каждое ребро e E появляется один раз как {vi , vi 1} для некоторого i. Если граф имеет цикл, содержащий все ребра графа по одному разу, то такой цикл называется эйлеровым циклом. Необходимое и достаточное условие существования эйлерова пути: эйлеров путь в графе существует тогда и только тогда, когда граф связан и содержит не более чем две вершины нечетной степени. Если в графе нет вершин нечетной степени, то каждый эйлеров путь является эйлеровым циклом. Пусть G = <V, E> – связный граф, представленный списками СПИСОК[r], v V. Алгоритм нахождения эйлерова цикла в графе построим следующим образом. Используем два стека: СТЕК1 и СТЕК2.
Выбираем произвольную вершину графа v0 и строим последовательно путь из этой вершины. Вершины этого пути помещаем в СТЕК1, а ребра удаляем из графа. Эти действия продолжаем до тех пор, пока оказывается, что путь удлинить, включив в него новую вершину, уже нельзя. Т.е. СПИСОК[v] = . Отметим, что тогда должно быть v v0 , иначе это бы означало, что вершина v – нечетной степени. Таким образом из нашего графа был удален цикл, а вершины этого цикла находятся в стеке СТЕК1. При этом в графе, модифицированном таким образом, степень произвольной вершины остается
четной. Вершина |
переносится теперь из стека СТЕК1 в стек СТЕК2, а процесс |
|
v v0 |
повторяется, начиная с вершины, верхней в СТЕК1 (если ее список не пустой). Теперь снова в СТЕК1 помещается некоторый цикл, проходящий через эту вершину, и т.д. Процесс продолжается до тех пор, пока СТЕК1 не станет пустым. Очевидно, что вершины, помещенные в СТЕК2, образуют некоторый путь, причем вершина v переносится в СТЕК2 только тогда, когда СПИСОК[v] = , т.е. когда все ребра, инцидентные этой вершине, представлены в СТЕКе1 (парами соседних вершин). Отсюда следует, что по окончании алгоритма СТЕК2 содержит эйлеров цикл. общая Сложность алгоритма O(m). Алгоритм считается оптимальным.
Эйлеров путь в графе - произвольный путь, проходящий через каждое ребро графа ровно один раз, т.е. такой путь Vj,..., Vm+1, что каждое ребро Е появляется один раз как { Vj ,V -+ j } для некоторого i. Если Vj = Vm+1, то такой путь называется эйлеровым циклом.
Необходимое и достаточное условие существования эйлерова пути: эйлеров путь в графе существует тогда и только тогда, когда граф связан и содержит не более чем две вершины нечетной степени.
Если в графе нет вершин нечетной степени, то каждый эйлеров путь является эйлеровым циклом.
Пусть G = <V, Е> - связный граф, представленный списками СПИСОК[г], ve V. Алгоритм нахождения эйлерова цикла в графе построим следующим образом. Используем два стека: СТЕК1 и СТЕК2.
Выбираем произвольную вершину графа VQ и строим последовательно путь из этой вершины. Вершины этого пути помещаем в СТЕК1, а ребра удаляем из графа. Эти действия продолжаем до тех пор, пока оказывается, что путь удлинить, включив в него новую вершину, уже нельзя. Т.е. СПИСОК[у] = 0. Отметим, что тогда должно быть V = VQ , иначе это бы означало, что вершина v - нечетной степени. Таким образом из нашего графа был удален цикл, а вершины этого цикла находятся в стеке СТЕК1. При этом в графе, модифицированном таким образом, степень произвольной вершины остается четной. Вершина V = v0 переносится теперь из стека СТЕК1 в стек СТЕК2, а процесс повторяется, начиная с вершины, верхней в СТЕК1 (если ее список не

пустой). Теперь снова в СТЕК1 помещается некоторый цикл, проходящий через эту вершину, и т.д. Процесс продолжается до тех пор, пока СТЕК1 не станет пустым.
Очевидно, что вершины, помещенные в СТЕК2, образуют некоторый путь, причем вершина v переносится в СТЕК2 только тогда, когда СПИСОК[у] = 0, т.е. когда все ребра, инцидентные этой вершине, представлены в СТЕКеl (парами соседних вершин). Отсюда следует, что по окончании алгоритма СТЕК2 содержит эйлеров цикл.
Алгоритм:
1BEGIN
2СТЕК1 := 0; СТЕК2 := 0;
3v := произвольная вершина графа;
4СТЕК1 <= v;
5WHILE СТЕК1 /0DO BEGIN
6v := top(СТЕКl); {v - верхний элемент СТЕК1}
7IF СПИСОК[у] Ф 0
8THEN BEGIN
9u := первую вершину списка СПИСОК[у];
10СТЕК1 <= u;
11СПИСОК^] := СПИСОК^] \ { u }; {удалить ребро}
12СПИСОКи] := СПИСОКи] \ { v }; {{ v, и } из графа}
13v :=и;
14END
15ELSE { СПИСОК[у] = 0}
16BEGIN
17v <= СТЕКl;
18СТЕК2 <= v;
19END
20END
21END
Мы предполагаем здесь, что каждый из списков инцидентности СПИСОК[у], veV, реализован таким образом, что каждая вершина в этом списке содержит указатели на предыдущую и последующую вершины, а вершина и в списке СПИСОК[у] содержит указатель на вершину v в списке СПИСОК[и]. Это дает возможность удалить ребро {v, и} за число шагов, ограниченное константой. Тогда можно оценить вычислительную сложность алгоритма следующим образом.
Каждая итерация главного цикла (строка 5) либо помещает вершину в СТЕК1 и удаляет ребро из графа, либо переносит вершину из СТЕК1 в СТЕК2. Т.е. число итераций этого цикла О(т). Число же шагов в каждой итерации ограничено константой. Поэтому можно считать, что общая сложность алгоритма О(т). Алгоритм считается оптимальным.
Пример.
Эйлеров цикл, найденный с помощью нашего алгоритма: 1, 2
56.Множествофундаменталных циклов графа. Алгоритм нахождения множества фундаментальных циклов.
Если к стягивающему дереву <V, T> графа G = <V, E> мы добавим произвольную хорду e E\T, то возникший при этом подграф C = <V, T {e}> содержит в точности один цикл (под циклом мы здесь будем понимать элементарный цикл). Обозначим этот цикл через Ce. Множество C = {Ce : e E \ T} называют фундаментальным множеством циклов графа G (относительно стягивающего дерева <V, T>). Алгоритм основан на поиске в глубину и имеет структуру, аналогичную рекурсивному алгоритму нахождения стягивающего дерева.
Каждая новая вершина, встречающаяся в процессе поиска, помещается в стек, представленный таблицей СТЕК, и удаляется из стека после использования. Очевидно, что стек всегда содержит последовательность вершин от рассматриваемой в данный момент вершины v к корню.
Поэтому, если анализируемое нами ребро {v, u} замыкает цикл (т.е. WGN[v] > WGN[u] > 0 b u не находится непосредственно под верхним элементом стека), то вершина u находится в стеке и цикл, замыкаемый ребром {v, u}, представлен группой элементов стека, начиная с v и кончая вершиной u.
1.PROCEDURE цикл(v);
{переменные d, num, СТЕК, СПИСОК, WGN - глобальные}
2.BEGIN d := d+1; СТЕК[d] := v; num := num+1; WGN[ ] := num;
3.FOR u СПИСОК[v] DO
4.IF WGN[u] = 0 THEN цикл(г)
5.ELSE IF (u СТЕК[d-1]) and (WGN[v] > WGN[u])
THEN {ребро {v, u} замыкает новый
цикл}
6. выписать цикл с вершинами
7. СТЕК[d], СТЕК[d-1], ..., СТЕК[c], где СТЕК[c] = u
8. d := d-1 {использованная вершина v удаляется из стека}
9.END (цикл};
Основная программа:
1.BEGIN
2. FOR v V DO WGN[r] := 0; num := 0; {инициализация}
3.d := 0; СТЕК[0] := 0; {d - число элементов в стеке}
4.FOR r V DO
5.IF WGN[r] = 0 THEN цикл(v)
6.END.
Отметим, что общее число шагов, не считая вычисления циклов, как и во всех алгоритмах, основанных на поиске в глубину, имеет порядок O(n+m). К этому следует добавить суммарную длину всех циклов. Эта длина не превосходит (m-n+1), что дает общую сложность алгоритма O(nm+n) (или O(nm), если отбросить вырожденный случай m=0).
Процедуры поиска в глубину и в ширину можно использовать для нахождения стягивающих деревьев. В обоих случаях достижение из вершины v новой вершины u вызывает включение в дерево ребра {v, u}. Вспомним, что деревом называется
произвольный неориентированный связный граф без циклов. Для произвольного неориентированного графа G = <V, E> каждое дерево <V, T>, где T E, будем называть стягивающим деревом или каркасом графа G. Ребра такого графа (дерева) назовем ветвями, а остальные ребра графа G будем называть хордами. Отметим, что каждое дерево с n вершинами имеет n-1 ветвь. (В каждую вершину, кроме корня, входит только одно ребро). Процедуры поиска в глубину и в ширину можно использовать для нахождения стягивающих деревьев. В обоих случаях достижение из вершины v новой вершины u вызывает включение в дерево ребра {v, u}.
BEGIN
FOR u V DO НОВЫЙ[u] := true;
{инициализация}
T := ; {множество найденных к этому времени ветвей}
ОЧЕРЕДЬ := ; ОЧЕРЕДЬ <= r;
НОВЫЙ[r] := false; {r - корень стягивающего дерева}
WHILE ОЧЕРЕДЬ DO BEGIN v <= ОЧЕРЕДЬ;
FOR uСПИСОК[u] DO
IF НОВЫЙ[u] THEN BEGIN
ОЧЕРЕДЬ <= u; НОВЫЙ[u] := false; T :=
T {v, u} END
END END
Данный алгоритм корректно строит стягивающее дерево для произвольного связного графа за O(n+m) шагов, т.е. за число шагов не более, чем С(n+m).
Преимущества процедуры поиска в ширину, приводят к следующему выводу. Пусть <V, T> - стягивающее дерево произвольного связного графа G = <V, E>, построенное с
помощью алгоритма поиска в ширину. Тогда путь в <V, T> из произвольной вершины v к корню r является кратчайшим путем из v к r в графе G.
Если к стягивающему дереву <V, T> графа G = <V, E> мы добавим произвольную хорду e E\T, то возникший при этом подграф C = <V, T {e}> содержит в точности один цикл. Обозначим этот цикл через Ce. Множество C = {Ce : e E \ T} называют фундаментальным множеством циклов графа G (относительно стягивающего дерева <V, T>). Название "фундаментальное" связано с тем, что каждый цикл графа G можно достаточно просто получить из циклов множества G.
Нахождение фундаментального множества циклов имеет прикладное значение, например, при анализе электрических цепей. А именно, каждому фундаментальному циклу в графе, соответствующему данной электрической цепи, мы можем поставить в соответствие закон Кирхгофа для напряжений: сумма падения напряжений вдоль цикла равна 0. Нахождение фундаментального множества циклов позволяет выделить в математическом описании цепи независимые уравнения.
Алгоритм нахождения множества фундаментальных циклов основан на поиске в глубину и имеет структуру, аналогичную рекурсивному алгоритму нахождения стягивающего дерева.
Каждая новая вершина, встречающаяся в процессе поиска, помещается в стек, представленный таблицей СТЕК, и удаляется из стека после использования. Очевидно, что стек всегда содержит последовательность вершин от рассматриваемой в данный момент вершины v к корню.
Поэтому, если анализируемое нами ребро {v, и} замыкает цикл, то вершина и находится в стеке и цикл, замыкаемый ребром {v, и}, представлен группой элементов стека, начиная с v и кончая вершиной и.
1PROCEDURE цикл(У);
{переменные d, пит, СТЕК, СПИСОК, WGN - глобальные}
2BEGIN d := d+1; СТЕК[d] := v; пит := num+1; WGN[ ] := пит;

3FOR uеСПИСОК[у] DO
4IF WGN[u] = 0 THEN цикл(г)
5ELSE IF (и Ф СТЕК[d-l]) and (WGN[v] > WGN[u])
|
THEN {ребро {v, и} замыкает новый цикл} |
6 |
выписать цикл с вершинами |
7 |
СТЕК[d], СТЕК[d-l], ..., СТЕК[с], где СТЕК[с] = и |
8d := d-1 {использованная вершина v удаляется из стека}
9END (цикл};
Основная программа:
1 BEGIN
2FOR veV DO WGN[r] := 0; num := 0; {инициализация}
3d := 0; СТЕК[0] := 0; {d - число элементов в стеке}
4FOR reV DO
5IF WGN[r] = 0 THEN цикл(у)
6END.
57.Алгоритм Варшалла.
Транзитивн замык. ориентир графа с n вершинами можно опр-ть как булеву матрицу, в которой Эл-т на пересечении i,j =1 если существует транзитивный путь и 0 если не сущет. Транзитивное замыкание можно построить с помощью поиска в ширину или глубину.
G=(V,E)Транзитивное замыкание ориентированного графа с n вершинами можно определить как булиеву матрицу Т размера n*n, в кот. Элемент на пересечении i-той строки и j-того столбца равен 1, если сущ-ет ориент.путь положительной длины из
вершины I в вершину j.В противном случае это значение равно 0. |
А- |
|||||||||||
матрица смежности. |
|
|
|
|
|
|
|
|||||
|
0 |
1 |
0 |
0 |
|
|
1 |
1 |
1 |
1 |
|
|
А |
0 |
0 |
0 |
1 |
Т |
|
1 |
1 |
1 |
1 |
В.предложил строить транзит.замыкание как |
|
|
0 |
0 |
0 |
0 |
|
|
0 |
0 |
0 |
0 |
|
|
|
1 |
0 |
1 |
0 |
|
|
1 |
1 |
1 |
1 |
|
|
последовательность матриц размера n*n –элемент матрицы
содержит 1, если есть путь из I в j, причем все промежут.верш.не превыш.номера k. Матрица
содержит инф. о путях между вершинами гр., в кот. в кач.промежуточной верш.может использоваться только вершина 1.
. Если существует путь от I до j и от k до j, то сущ-ет путь от k до i-появл.1.
|
|
0 |
1 |
0 |
|
0 |
|
|
0 |
1 |
0 |
0 |
|
0 |
1 |
0 |
1 |
|
0 |
1 |
0 |
1 |
R(0) |
|
0 |
0 |
0 |
|
1 |
R(1) |
|
0 |
0 |
0 |
1 |
R(2) |
0 |
0 |
0 |
1 |
R(3) |
0 |
0 |
0 |
1 |
|
|
0 |
0 |
0 |
|
0 |
|
|
0 |
0 |
0 |
1 |
|
0 |
0 |
0 |
0 |
|
0 |
0 |
0 |
0 |
|
|
1 |
0 |
1 |
|
0 |
|
|
1 |
0 |
1 |
0 |
|
1 |
1 |
1 |
1 |
|
1 |
1 |
1 |
1 |
|
1 |
1 |
|
1 |
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
R(4) |
1 |
1 |
|
1 |
1 |
T |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0 |
0 |
|
0 |
0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
1 |
|
1 |
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

Алгоритм Wavshell(A[1..n]*A[1..n])
1.R(0)A; 2.for k=1 to n do 3.for i=1 to n do 4.for j=1 to n do 5.R(k)[I,j]R(k-1)[I,j] or (R(k-1)[I,k] and R(k-1)[k,j];end for;end for;end for;retirn R(n) Вычислит.сложность=О(n3)
58. Стягивающие деревья. Нахождение стягивающего дерева методом поиска в глубину.
Стягивающие деревья-см вопр 60. Рассмотрим алгоритм нахождения стягивающего дерева связного графа методом поиска в глубину. Пусть исходный граф G = <V, E> задан списками инцидентности СПИСОК[v], v V. Алгоритм реализуем процедурой WGD(v):
1.PROCEDURE WGD(v);
{Перем. НОВЫЙ, СПИСОК, Т (множество ветвей) - глобальные}
2.BEGIN НОВЫЙ[v] := false; 3.FOR u СПИСОК[v] DO
4.IF НОВЫЙ[u] THEN BEGIN
5.T := T {v, u}; {добавить новую ветвь}
6.WGD(u)
7.END
8.END {WGD};
Основная программа
1.BEGIN
2.FOR u V DO НОВЫЙ[u] := true; {инициализация}
3.T := ;
4.WGD( r ) {r - произвольная вершина}
5.END
1)в момент добавления к множеству Т новой ветви {v, u} (строка 5 WGD) в дереве <V, T> существует путь из r в v. Таким образом алгоритм строит связанный граф;
2)каждая новая ветвь {v, u}, добавляемая к множеству Т, соединяет уже рассмотренную вершину v с новой вершиной u. Отсюда следует, что построенный граф <V, T> не имеет циклов. (Действительно, последняя ветвь, замыкающая цикл, должна была бы соединить две уже рассмотренных вершины);
3)из свойства поиска в глубину следует, что программа WGD просматривает все вершины связного графа.
Очевидно, что вычислительная сложность алгоритма будет порядка С(n+m).
Для произвольного неориентированного графа G = <V, Е> каждое дерево <V, Т>, где ТсЕ, будем называть стягивающим деревом или каркасом графа G. Ребра такого графа (дерева) назовем ветвями, а остальные ребра графа G будем называть хордами.
Поиск в ширину. О(n+m)
1.BEGIN
2.FOR u V DO НОВЫЙ[u] := true; {инициализация}
3.T := ; {множество найденных к этому времени ветвей}
4.ОЧЕРЕДЬ := ; ОЧЕРЕДЬ r;
5. НОВЫЙ[r] := false; {г - корень
стягивающего дерева} |
|
6.WHILE ОЧЕРЕДЬ |
DO BEGIN |