Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
РП_31_АСД.pdf
Скачиваний:
164
Добавлен:
23.02.2016
Размер:
2.92 Mб
Скачать

Тема 26. ОБХІД ГРАФУ: ПОШУК ВГЛИБИНУ

Численна кількість алгоритмів на графах ґрунтується на переборі всіх або частини їх вершин. Такий перебір називається обходом графу. Найвідоміші алгоритми обходу графу – це пошук вглибину і вшир.

Пошук вглибину

Алгоритм пошуку вглибину розглядатиметься для зв’язного неорієнтованого графу. Пошук починається із заданої стартової вершини і триває доти, доки не буде знайдено певної кінцевої вершини або поки є вершини, що утворюють маршрут пошуку. Нехай стартова вершина позначена літерою v. Обирається довільне ребро (v,u), інцидент не v. Якщо вершина u вже відвідана, то обирається інше ребро, що є інцидентним v. У протилежному випадку вершина u вважається стартовою і повторюється процедура пошуку. Якщо пошук з вершини u завершується безуспішно, то відбувається повернення до вершини v і продовжується пошук ребер, інцидентних вершині v і таких, що раніше не відвідувалися. Вибір нових ребер триває доти, доки не вичерпаються всі ребра, що є інцидентними v, або пошук кінцевої вершини не завершиться успішно.

Слід зауважити, що під час пошуку вглибину в орієнтованому графі переглядаються лише ті дуги, що виходять зі стартової вершини.

Оцінки часової складності алгоритму пошуку вглибину

Нехай граф має n вершин і m ребер. Пошук вершини, що не була відвідана, виконується не більше ніж за О(n) кроків, а кількість кроків, що їх необхідно здійснити для перебору всіх інцидентних певній вершині ребер, становить не більше ніж О(m). Отже, часова складність пошуку вглибину становить О(n+m).

Приклад.

Нехай структура графу зберігається в текстовому файлі, перший рядок якого містить кількість вершин графу, а кожний наступний рядок – два числа, що є номерами певних суміжних вершин. Тобто кожен рядок файлу, починаючи з другого, визначає ребро графу. Номери стартової та кінцевої вершин користувач вводить з клавіатури.

Для зображення графу використовується список суміжності. Тип вершини називається TVer. Запис типу TVer містить такі поля: поточний номер вершини, кількість суміжних із нею вершин, масив покажчиків на суміжні вершини, ознаку відвідування вершин. Сам граф задається масивом a, елементи якого будуть покажчиками на записи TVer.

Ініціалізація масиву вершин даними, що зчитані з текстового файлу. Виконується у процедурі Init, з якої викликається процедура зв’язування суміжних вершин LinkVertex. Слід звернути увагу на те, що одному ребру відповідають два зв’язки між вершинами, оскільки алгоритм розглядається для неорієнтованого графу.

Власне пошук вглибину здійснює рекурсивна процедура Search, яка є локальною щодо процедури DepthFirstSearch (пошук вглибину). У процедурі DepthFirstSearch запрограмовані введення початкової та кінцевої вершин для пошуку, помітка початкової вершини, як такої. Що вже опрацьована, і всіх інших вершин, як таких, що потребують перегляду, а також виклик процедури Search.

program Yrok12_1;

{пошук вглибину}

{$APPTYPE CONSOLE}

 

uses SysUtils;

 

type

 

PtrVer=^TVer;

{тип покажчика на вершину}

TVer=record

{тип вершини графу}

93

vertex: array[1..50] of PtrVer;

{масив покажчиків на суміжні вершини}

k,

 

 

 

{кількість суміжних вершин }

number: integer;

 

 

{номер вершини}

mark: boolean;

 

 

{ознака відвідування вершини}

end;

 

 

 

 

var a: array[1..50] of PtrVer;

 

{масив покажчиків на вершини графу}

n: integer;

 

 

 

{кількість вершин графу}

t: text;

 

 

 

{файлова змінна}

key: char;

 

 

 

{символ обраної користувачем дії}

start, finish: integer;

 

{номери стартової та кінцевої вершин обходу графу}

{Встановлення зв’язків між вершинами графу}

procedure LinkVertex(var v,u: PtrVer);

begin

 

 

 

 

inc(v^.k);

v^.vertex[v^.k]:=u;

{включити u в список суміжності v}

inc(u^.k);

u^.vertex[u^.k]:=v;

{ включити v в список суміжності u }

end;

 

 

 

 

{Ініціалізація графу з файлу}

 

procedure Init;

 

 

 

var i,

 

{параметр циклу}

iv,iu: integer;

{номери суміжних вершин}

Ver: PtrVer;

{покажчик на фершину графу}

begin

 

 

 

 

assign(t,'graph.txt');

 

 

 

reset(t);

 

{відкриття файлу для читання суміжних вершин}

readln(t,n);

{читання кілкості вершин графу}

for i:=1 to n do

{створення масиву покажчиків на вершини графу}

begin

 

 

 

 

new(Ver);

{виділення пам'яті для покажчика на вершину}

Ver^.number:=i;

{визначення номеру вершини}

Ver^.k:=0;

{задання кількості суміжних вершин}

a[i]:=Ver;

{запис покажчика на вершину в масив}

end;

 

 

 

 

while not eof(t) do

{поки не досягнуто кінця файлу}

begin

 

 

 

 

readln(t,iv,iu);

{читання номерів суміжних вершин}

LinkVertex(a[iv],a[iu]);

{зв’язування вершин}

end;

 

 

 

 

close(t);

 

{закриття файлу}

end;

 

 

 

 

{пошук вглибину}

 

 

 

procedure DepthFirstSearch;

 

 

var w: array[1..50] of integer;

{масив номерів вершин маршруту}

i,j: integer;

 

{лічильники циклів}

{алгоритм пошуку вглибину}

 

procedure Search(V: PtrVer); {v – покажчик на початкову вершину}

var i: integer;

 

{ лічильник циклу}

begin

 

 

 

 

94

if V^.number=finish

{якщо досягнуто кінцевої вершини}

then begin

 

 

 

 

write('Path: >> ');

{виведення маршруту}

for i:=1 to j do

 

 

 

 

begin

 

 

 

 

write(w[i]);

 

 

 

 

if i<j then write('->');

 

 

 

end;

 

 

 

 

writeln;

 

 

 

 

exit;

 

 

 

 

end

 

 

 

 

else

 

{ якщо не досягнуто кінцевої вершини }

for i:=1 to v^.k do

{перегляд усіх суміжних вершин}

 

begin

 

 

 

 

if not V^.vertex[i]^.mark

{якщо поточна суміжна вершина не позначена}

 

then begin

 

 

 

 

 

v^.vertex[i]^.mark:=true;

 

{позначення вершини}

 

 

j:=j+1;

{збільшення лічильника позначених вершин}

 

 

w[j]:=v^.vertex[i]^.number;

{збереження номеру вершини}

 

 

Search(v^.vertex[i]);

{перехід до наступних вершин}

 

 

j:=j-1;

{ зменшення лічильника позначених вершин }

 

 

v^.vertex[i]^.mark:=false;

 

{ зняття позначення вершини }

 

end;

end;

 

 

 

end;

 

 

 

 

 

 

 

 

 

{основний блок процедури пошуку вглибину}

begin

 

 

 

 

 

writeln('<<<<depth first search>>>>');

 

 

writeln('**************************');

 

 

write('initial vertex: '); readln(start);

 

 

write('terminal vertex: '); readln(finish);

 

for i:=1 to n do

{зняття позначення вершин}

a[i]^.mark:=false;

 

 

 

a[start]^.mark:= true;

{позначення стартової вершини}

j:=1;

 

 

 

 

 

w[j]:=start;

{збереження номеру стартової вершини}

Search(a[start]);

{виклик рекурсивної процедури пошуку}

readln;

 

 

 

 

 

end;

 

 

 

 

 

{основний блок програми}

 

 

begin

 

 

 

 

 

Init;

{створення графу}

 

 

Repeat

 

{нескінчений цикл}

 

 

writeln('Number of vertexes=',n); writeln('**************************'); writeln('press <Enter> to solution'); writeln('<x> - to exit');

95

readln(key); case key of

#13: DepthFirstSearch; {натиснуто клавішу Enter}

‘x’: halt;

{ натиснуто клавішу ‘x’}

end;

 

until false;

 

end.

 

Для даних: 5

13

14

23

25

34

отримано наступний рез ультат:

96