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

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

За алгоритмом пошуку вшир здійснюється обхід графу в порядку збільшення відстані від стартової вершини. Відстань між вершинами a і b вважається рівною кілкості ребер на найкоротшому шляху від a до b. Отже, спочатку переглядається стартова вершина, потім – суміжні з нею вершини, що входять до списку перегляду. Кожні ітерація алгоритму полягає в послідовному виборі всіх вершин зі списку перегляду і додаванні до цого списку вершин, що є суміжними з вибраними. При цому вершини не можуть переглядатися двічі, а тому під час перегляду вершину слід позначати. Позначені вершини надалі не розглядаються.

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

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

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

Пошук ушир вершини finish, що розпочинається з вершини start, виконує процедура BreadFirstSearch. Усі вершини, що є суміжними з поточною і не були позначені, додаються до черги за допомогою процедури AddList. Черга переглядається, починаючи від вершини PCur. Тому виконання оператора PCur:=PCur^.Next є дією, логічно еквівалентною видаленняю вершини з черги. У разі знаходження кінцевої вершини або вичерпування всіх можливостей пошуку, чергу слід очистити за допомогою процедури Clear. Нарешті, рекурсивна процедура Output здійснює виведення знайденого шляху. Для посилання на попередню вершину використовується покажчик Prev.

program yrok12_2;

{пошук ушир}

 

{$APPTYPE CONSOLE}

 

uses SysUtils;

 

 

type

 

 

PtrVer = ^TVer;

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

TVer = record

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

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

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

k,

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

number : integer;

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

mark : boolean;

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

end;

 

 

PElem = ^TElem;

{тип покажчика на елемент черги}

TElem = record

{тип елемента черги}

PVer : PtrVer;

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

PFrom: PElem;

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

Prev,

{покажик на попередній елемент черги}

Next : PElem;

{покажчик на наступний елемент черги}

end;

 

 

var PBeg, PEnd,

{покажчики на початок та кінець черги}

97

PCur : PElem;

{покажчик на поточний елемент черги}

t : text;

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

key : char;

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

start,finish : integer;{ номери стартової та кінцевої вершин обходу графу } a : array[1..50] of PtrVer; { масив покажчиків на вершини графу }

n : 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 AddList(v : PtrVer; q : PElem);

{v – покажчик на вершину, що додається до черги} {q – покажчик на попередній елемент черги}

var p : PElem; {поточний покажчик} begin

new(p);

{виділення пам'яті для елемента черги}

p^.PVer:=v;

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

p^.PFrom:=q;

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

p^.Prev:=PEnd^.Prev; {зв’язування поточного і кінцевого елементів черги} p^.Next:=PEnd;

PEnd^.Prev^.Next:=p; {}

98

PEnd^.Prev:=p;

{}

end;

 

{Видалення елемента з черги} procedure DelList(e : pElem);

{е – покажчик на елемент, що видаляється}

var p : PElem;

 

 

begin

 

 

if e = nil then exit;

{якщо елемент порожній, то – вихід з програми}

e^.Next^.Prev:=e^.Prev;

{переадресація покажчика }

e^.Prev^.Next:=e^.Next;

 

dispose(e);

{вивільнення пам'яті з-під елемента}

end;

 

 

{Виведення поточного елемента черги}

procedure Output(e : pElem);

 

begin

 

 

if e = nil then exit;

{ якщо елемент порожній, то – вихід з програми }

output(e^.PFrom);

{виведення решти елементів черги}

if e^.PVer^.number <> finish

 

 

then write(e^.PVer^.number,' -> ')

{якщо елемент є останнім}

else write(e^.PVer^.number,' ');

{ якщо елемент не є останнім }

end;

 

 

 

{Видалення черги}

 

 

 

procedure Clear;

 

 

 

var PCurrent, PDel : PElem;

 

 

begin

 

 

 

PCurrent:=PBeg^.Next;

 

 

while PCurrent <> PEnd do

{поки не досягнуто кінця черги}

begin

 

 

 

PDel:=PCurrent;

 

{покажчик на елемент, що видаляється}

PCurrent:=PCurrent^.Next;

{переадресація покажчика на наступний елемент}

DelList(PDel);

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

end;

 

 

 

end;

{Пошук ушир}

procedure BreadFirstSearch; var i : integer;

begin clrscr;

writeln('<<<<Bread First Search>>>>'); writeln('**************************'); write('inicial vertex : '); readln(start); write('terminal vertex: '); readln(finish);

AddList(a[start], nil);

{додавання вершини до черги}

for i:=1 to n do a[i]^.mark:=false;

{позначення вершин графу, як такі, що не відвідані}

PCur:=PBeg^.Next;

{вибір початку черги}

while PCur <> PEnd do

{поки не досягнуто кінці черги}

begin

 

 

 

99

PCur^.PVer^.mark:=tr ue; {позначення відвіданої вершини графу}

if PCur^.PVer^.number = finish then

{якщо вершина є останньою в черзі}

begin

 

 

write('Path : >>');

 

 

output(PCur);

{виведення черги}

clear;

{очищення черги}

readln;

 

 

exit;

{вихід з процедури}

end;

 

 

{ якщо вершина не є ост анньою в черзі }

 

for i:=1 to PCur^.PVer ^.k do

 

begin

 

 

if not PCur^.PVer^.v ertex[i]^.mark

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

then AddList(PCur^.PVer^.vertex[i],PCur);

end;

 

 

PCur:=PCur^.Next;

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

end;

 

 

writeln('<<< Path not foun d >>>');

readln;

clear; { очищення черги } end;

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

new(PBeg); new(PEnd); PBeg^.Prev:=nil; PBeg^. Next:=PEnd; PEnd^.Prev:=PBeg; PEndd^.Next:=nil; init;

repeat

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

readln(key); case key of

#13: BreadFirstSearch; ‘x’: halt;

end; until false; end.

Для даних: 5

13

14

23

25

34

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

100