Скачиваний:
37
Добавлен:
30.05.2020
Размер:
3.32 Mб
Скачать

1

0

0

0

0

0

1

2

1

0

0

1

0

0

3

1

1

0

0

0

1

4

0

0

0

0

0

0

5

0

0

0

0

0

0

6

0

0

0

0

1

0

б)

Мал. 40

на малюнку 41, а. Для фіксації переглянутих вершин, згідно з алгоритмом пошуку в глибину, використовуватимемо множи­ ну, куди на першому кроці запишемо вершину 1. Відповідно до таблиці суміжності вона має ребро з вершиною 6. Перейдемо до неї, записавши наступною в послідовності переглянутих вер­ шин (мал. 41, в).

З вершини 6 далі ми можемо рухатися лише у вершину 5. Дописуємо її в множину й в послідовність переглянутих вер­ шин (мал. 41, в).

Мал. 41

Вершина 5 є тупиковою, тому визначимо її як елемент тополо­ гічного сортування вершин графа і зафіксуємо її номер у другому рядку на малюнку 42, а. Повернемося до попередньої вершини у послідовності переглянутих вершин, якою є вершина 6. Верши­ на 6 також є тупиковою, оскільки, окрім вершини 5, ніяких інших

82

Мал. 42

вершин з неї не видно. Виведемо її в другий рядок (мал. 42, б). Переходимо до вершини 1, яка також заводить нас у тупик. Фіксуємо її як елемент топологічного сортування і вилучаємо

зпослідовності переглянутих вершин (мал. 42, в). Послідовність переглянутих вершин вичерпано, але ще не

всі вершини графа переглянуті. Тому продовжимо наш пошук далі. Наступною вершиною логічно розглянути вершину 2: в ній ми ще не були і її номер наступний за значенням. Запише­ мо її в послідовність переглянутих вершин на першу позицію і занесемо в множину (мал. 43, а).

З вершини 2 першою можна побачити вершину 1. Але пере­ ходити в неї не можна, оскільки ми вже в ній побували. На­ ступною за значенням вершиною, в яку можна перейти з 2, є 4. Вона нова, тому здійснимо цей крок (мал. 43, б). Тепер уже вер­ шина 4 стає тупиком. Перенесемо її в топологічно відсортовану послідовність і перейдемо до вершини 2 (мал. 43, в).

Мал. 43

83

Мал. 43 (продовження)

Вершина 2 - тупикова. Перепишемо її номер у другий ря­ док, а наша послідовність переглянутих вершин (перший ря­ док) знову стає порожньою (мал. 44, а). Оскільки ще не всі вер­ шини нашого графа переглянуті, то доводиться шукати наступ­ ну нову вершину. Такою є вершина 3. Запишемо її першою у послідовність переглянутих вершин і занесемо в множину (мал. 44, а).

З вершини 3 хоча і є ребра до трьох вершин - 1,2,6, однак вони вже всі були переглянуті, тому це тупик. Згідно з нашим алго­ ритмом ми фіксуємо вершину 3 як останній елемент у тополо­ гічно відсортованій послідовності і повертаємо до попереднього елемента у послідовності переглянутих верпіин (мал. 44, в). Це останній крок алгоритму, оскільки всі вершини переглянуті і послідовність переглянутих вершин вичерпано.

У другому рядку на малюнку 44, в міститься результат ви­ конання алгоритму топологічного сортування у зворотному

Мал. 44

84

Мал. 45

порядку. Зобразимо нашу відповідь 3, 2, 4, 1, 6, 5, де вказано ребра, які існують між цими вершинами в заданому графі (мал. 45). Як бачимо, умова топологічного сортування вершин графа виконується.

А тепер реалізація запропонованого алгоритму мовою про­ грамування:

 

{Ініціалізація початку роботи програми:}

top := 1; а[1] := k;

{top - вершина стеку; а - стек,}

 

{s - множина відвіданих вершин;}

s := [k]; count := 0; і := 1;

{count- лічильник сортування.}

while (top > 0) Or (s <> [1 ..n]) do {Пошук нових невідвіданих вершин графа.}

begin

while (І <= n) do

{Пошук ребра, яке веде у нову невідвідану вершину.}

begin

 

 

if (d[a[top], І]=1) and not (І in s)

{Якщо таке існує, то}

then

 

 

begin

 

 

inc(top); a[top] := і;

{запис нової вершини у стек}

s := s + [і]; і := 1;

 

{і у множину.}

end

 

 

else Іпс(і)

 

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

end;

 

 

{Якщо поточна вершина є тупиковою,} inc(count); sort[count] :=a[top]; {то запис її у відсортовану послідовність}

dec(top);

 

{і зменшення значення вершини стеку.}

if (top = 0) and (s <> [1 ..n])

{Якщо стек порожній, але не всі вершини}

then

 

{графа відвідані, то}

begin

 

 

І := 1;

{пошук нової стартової вершини для продовження обходу графа:}

while І in S do Іпс(і);

{вибір нової невідвіданої вершини;}

inc(top); a[top] := і;

{запис її у стек}

s := s + [ і ] ; і := 1;

{і у множину відвіданих вершин;}

end

 

{початок пошуку існуючих ребер з цієї вершини.}

else і := 1; {Стек не порожній - початок пошуку існуючих ребер з поточної вершини.}

end;

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

85

3 2

2 1

24

16

36

6 5

3 1 Оскільки представлений граф є орієнтованим, то опис кожно­

го ребра вказує його напрям: перша вершина в указаній парі - це початок ребра, тобто вихідна вершина, а друга - його кінець, або вхідна вершина. Розглянемо номери вершин, що є вхідни­ ми, тобто другий стовпчик у вхідній інформації про заданий граф. У ньому вказано номери вершин, у які входять ребра, тобто ці вершини є нащадками тих вершин, які вказані як від­ повідні вихідні. А що можна сказати про номери вершин, які не зафіксовані як вхідні? Це ті вершини, які не є нащадками, а значить, вони самі можуть мати лише нащадків. Для нашого прикладу такою є вершина 3. Виведемо її першою під час топо­ логічного сортування. Оскільки вершина 3 нами вже опрацьо­ вана, приберемо в графі ребра, які з неї виходять (мал. 46, а). Відповідно скоректуємо вхідну інформацію, вилучивши ті реб­ ра, які мають вихідними вершинами вершину 3. Подивимося знову на граф і визначимо, які вершини тепер не є нащадками. У другому стовпчику скоректованої вхідної інформації з'яви­ лася ще одна відсутня вершина 2. Це означає, що тепер вона не має нащадків і можна її записувати слідом за вершиною 3 у то­ пологічно відсортовану послідовність та вилучити ребра, у яких вершина 2 є вихідною (мал. 46, б).

Проаналізуємо нові відсутні ребра у графі, зображеному на малюнку 46, б. Тепер там немає вершин 1 та 4. Проведемо про­ цедуру, аналогічну до попередньої, з вершинами 1 і 4 (мал. 46, в). Тепер у нас залишилося тільки одне ребро (6,5). Новою відсутньою вершиною, що відіграє роль вхідної, є вершина 6. Вилучаємо останнє ребро, що залишилося в нас у списку ребер графа, і записуємо вершину 6 у топологічно відсортовану послі-

"$v

21

"ОЗ 24 16 65

а)

Мал. 46

86

jsr-ia-

 

ік

*

 

 

 

 

4

 

 

<]L

 

Ьз

 

 

 

 

 

л

3 2 1 4 6

 

ИГ""«ч

г)

 

 

 

 

 

 

 

4

£-#3

5Л0 3 2 1 4 6 5 д)

Мал. 46 (продовження)

довність (мал. 46, г). Ми фактично завершили сортування. У нас залишилась одна вершина 5, яку необхідно дописати ос­ танньою в нашу результуючу послідовність (мал. 46, д).

Ми отримали результат, який відрізняється від попередньо­ го лише послідовністю деяких вершин, однак ніяким чином не порушує умову топологічного сортування.

Запропонований алгоритм є досить простим з точки зору його розуміння, однак складнішим з точки зору реалізації. Чим є наша вхідна інформація? Списком ребер заданого графа. А яким чином ми її коректували? Вилучали зі списку необхідні ребра. Тому для реалізації цього алгоритму необхідно викорис­ тати таку структуру даних як список і передбачити можливість вилучення з нього елементів.

Фрагмент програми, що є реалізацією запропонованого алго­ ритму, може бути таким:

read(f _ in, П, Пґі);

{Введення кількості вершин і ребер графа.}

new(q); р := q;

{Визначення адреси початку списку ребер.}

fo r і := 1 to m - 1 do {Заповнення списку початковою інформацією про ребра графа.}

begin

read(f_in, рл .і, p".j); {Введення номерів вхідної і вихідної вершини поточного ребра.} {Визначення адреси розміщення в пам'яті}

new(p A . next);

{інформації про наступне ребро.}

р := p".next;

{Перехід до цієї адреси.}

e n d ;

 

read(f _ in, р p".j); p".next := nil;

{Запис інформації про останнє ребро.}

s : = [ 1 . . n ] ;

{Множина всіх вершин графа.}

 

{Сортування вершин графа, поки не будуть}

87

w h i l e S <> [] do

 

{переглянуті всі його вершини.}

b e g i n

 

 

 

s1 := s; p := q;

 

{Початок перегляду елементів списку.}

w h i l e p".next <> nil do

 

{Поки список не переглянутий до кінця,}

b e g i n

 

 

 

s1 := s1 - [p" .j]; {вилучення номера вхідної вершини поточного ребра списку;}

р := p".next;

 

{перехід до наступного ребра списку.}

end;

 

 

 

S := S - S1;

{Визначення номерів вершин, відсутніх у списку як вхідних.}

f o r і := 1 to n do

{Перегляд усіх вершин графа і виведення тих,}

if і in s1 t h e n write(f_OUt, І, ' ');

{що визначені як відсутні вхідні.}

р := q;

 

 

{Перехід у початок списку.}

 

 

 

{Перегляд елементів списку,}

w h i l e p".next О nil do

 

{поки не буде знайдено його кінець.}

if рЛ.І in S1

{Якщо номер вихідної вершини був визначений як номер вхідної, то}

t h e n

 

 

 

b e g i n

 

 

 

рл .І := p".next".i;

 

{вилучити цей елемент зі списку.}

p".j :=

p \ n e x t \ j ;

 

 

if p".next <> nil

 

{Якщо поточний елемент не є останнім,}

t h e n p".next := рЛ .next".next

{то перейти до адреси наступного,}

else р := pA .next

{у протилежному випадку визначити його адресу як nil.}

end;

 

 

 

e l s e р := p".next;

{Якщо номер вихідної вершини не є номером вхідної,}

e n d ;

 

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

Для коректної роботи наведеного фрагмента програми необ­ хідно організувати опис таких змінних:

t y p e list= / 4list; {Динамічний список, що містить інформацію про ребра графа:}

tlist = record

і, j : b y t e ;

{номер вихідної і вхідної вершин;}

next:list

{адресу інформації про наступне ребро.}

end;

Цікаво порівняти обидва підходи до топологічного сортуван­ ня вершин ациклічного орієнтованого графа.

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

Удругому алгоритмі ми весь час коректували список ребер графа, які вже переглянуті, виключаючи їх із цього списку. Якщо нам буде задано граф типу «зірочка», то даний алгоритм на першому ж кроці відкине всі ребра, у які входить вершина, що є центром цієї «зірочки», і алгоритм буде завершено. В алго­ ритмі ж з використанням пошуку в глибину нам доведеться

88

«гуляти» таблицею суміжності, переходячи в усі вершини, у які ведуть ребра з вершини, що є центром «зірочки». До речі, ще не відомо, як перенумеровані вершини: якщо центром «зірочки» не є вершина з номером 1, то довго будемо блукати таблицею суміжності, кожного разу потрапляючи в тупики.

Ще одна перевага другого алгоритму — він може опрацювати значно більший за кількістю вершин граф, особливо графи з великою кількістю ізольованих вершин. При цьому у вхідній інформації такі вершини будуть відсутні, оскільки вони не нале­ жать жодному ребру, а в таблиці суміжності їх необхідно враху­ вати. До єдиного недоліку другого алгоритму можна віднести не­ обхідність реалізації роботи з динамічним списком, що передба­ чає достатньо глибоке розуміння тих процесів, що відбуваються у пам'яті комп'ютера під час роботи безпосередньо з її адресами.

Оцінимо ефективність роботи обох розглянутих алгоритмів. Перший алгоритм базується на пошуку в глибину, тому його

оцінка становить 0(п + т).

Другий алгоритм пов'язаний з переглядом двох масивів вер­ шин графа: у другому масиві визначаються відсутні вершини, а в першому - виключення їх і відповідних їм вершин із друго­ го масиву. У кращому випадку на першому ж кроці буде пере­ глянуто два масиви вершин і виключено всі вершини. Оцінка такого варіанта становить О(п). У найгіршому випадку виклю­ чення вершин буде відбуватися по одній на кожному кроці алгоритму, що відповідає оцінці 0(п2). Середнє значення цих оцінок становитиме 0(п2/2).

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

Завдання

1.Розробити та реалізувати у вигляді програми алгоритм топо­ логічного сортування вершин заданого ациклічного орієнто­ ваного графа, використовуючи алгоритм пошуку в глибину.

2.Виконати завдання 1 для ациклічного орієнтованого графа з кількістю вершин N ^ 10. Результат виконання програми вивести у файл.

89

3.Виконати завдання 1 для ациклічного орієнтованого графа з кількістю вершин N = 100. Результат виконання програми вивести у файл.

4.Розробити та реалізувати у вигляді програми алгоритм топо­ логічного сортування вершин заданого ациклічного орієнто­ ваного графа, використовуючи структуру даних «список».

5.Виконати завдання 4 для ациклічного орієнтованого графа з кількістю вершин N ^ 10. Результат виконання програми вивести у файл.

6.Виконати завдання 4 для ациклічного орієнтованого графа з кількістю вершин N = 100. Результат виконання програми вивести у файл.

7. Зробити аналіз отриманих результатів.

/

 

Запитання для самоконтролю

1.Що розуміється під топологічним сортуванням вершин заданого графа?

2.Для вершин яких графів існує поняття топологічного сортуван-

Іня? Наведіть приклади.

3.Як називаються графи, що не мають циклів?

4.На якому алгоритмі базується один з алгоритмів топологічного сортування? Обґрунтуйте коректність своєї відповіді.

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

6.Виконайте попередньо описаний алгоритм покроково на конк­ ретному прикладі.

7.Запишіть фрагмент програми, що реалізує попередньо описа­ ний алгоритм.

8.Який ще можна запропонувати алгоритм топологічного сортуван­ ня? Яку вхідну інформацію про заданий граф він використовує?

9.На якій ідеї базується другий алгоритм топологічного сортування?

10.Обґрунтуйте коректність роботи другого алгоритму топологічного сортування на конкретному прикладі, виконавши його покроково.

11.Запишіть фрагмент програми, що реалізує другий алгоритм то­ пологічного сортування.

12.Порівняйте два варіанти алгоритмів топологічного сортування, відзначивши при цьому їх позитивні та негативні сторони.

Побудова остовного дерева

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

90

а)

б)

в)

 

 

Мал. 47

(мал. 47, а). Для економії витрат води вирішено було рекон­ струювати зрошувальну систему, прибравши в ній зайві рівча­ ки і залишивши мінімально необхідну їх кількість.

Давайте спочатку визначимо, у чому полягає суть задачі. Мінімальною буде така структура зрошувальної системи, коли всі дерева будуть з'єднані таким чином, що від першого визна­ ченого дерева буде йти рівчак до будь-якого іншого, потім до будь-якого іншого з тих, що залишились, і т. д. Скільки потріб­ но таких рівчаків? Якщо дерев у саду N, то зрозуміло, що рів­ чаків потрібно (N - 1). А чи можна це зробити у нашій задачі? Звісно, що можна, оскільки говорячи мовою графів, нам було задано зв'язний граф. А це означає, що всі дерева зрошувалися водою, а це свідчить про досяжність довільної його вершини з будь-якої іншої.

Отже, рішення полягає в тому, щоб залишити тільки ті реб­ ра графа, що з'єднають усі його вершини. У результаті також отримаємо граф, але він не буде містити циклів, оскільки почнемо його будувати з будь-якої вершини, пройшовши реш­ ту лише один раз.

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

На малюнках 47, б та 47, в зображені остовні дерева для гра­ фа, що зображений на малюнку 47, а. Отже, можна зробити висновок, що таких остовних дерев для одного і того самого графа може бути більше одного.

Перейдемо до розгляду алгоритму побудови остовного дере­ ва для заданого незваженого неорієнтованого зв'язного графа. Для цього скористаємося пошуком у глибину.

1.Визначити будь-яку вершину і як поточну і запам'ятати її першою у послідовності відвіданих вершин.

2.Визначити змінну count = 1 як лічильник кількості ребер

востовному дереві.

91

Соседние файлы в папке Методи побудови алгоритмів та їх аналіз