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

За алгоритмом повертаємося у вершину 2. У 2-му рядку таб­ лиці суміжності елементи 5 і 6 дорівнюють 1, що говорить про наявність ребер (2,5) та (2,6). Порядковий номер вершини 5 менший за порядковий номер вершини 2(1 < 4) і менший за її індекс (1 < 9), тому індекс вершини 2 тепер дорівнюватиме 1, а це означає, що з вершини 2 ми змогли побачити вершину з мен­ шим порядковим номером, ніж досі. Так само розглянемо і вер­ шину 6 - наступну видиму вершину з вершини 2. Однак індекс вершини 2 при цьому не покращиться, оскільки вершину 6 ми «зустріли» пізніше, ніж вершину 5 і її порядковий номер 3, що більший за 1 (мал. 70, б).

Переглянувши всі видимі вершини з вершини 2, ми не може­ мо побачити жодної нової. Це свідчить про те, що ми знову по­ трапили в тупик. Зменшуємо значення вершини стеку, переходя­ чи до вершини 6, і розглянемо ребро (6,2) на малюнку 71, а. По­ тенційно вершина 6 може бути точкою з'єднання. Для цього по­ винна виконатися умова orderG < ind2. Як бачимо з малюнка 70, б, цього не відбувається (3 > 1), тому перевіряємо виконання умови ind2 < inde. Ця умова для ребра (6,2) виконується, оскільки 1 < 2, тому, згідно з п. 11 описаного вище алгоритму, перевизначаємо індекс вершини 6, надаючи йому значення 1 (мал. 71, а). Тепер переходимо до перегляду 6-го рядка у таблиці суміжності. Оскільки у вершину 6 ми повернулися з вершини 2, де були роз­ глянуті всі попередні вершини, то у вершині 6 можемо починати розгляд видимих вершин, що слідують за вершиною 2. Новою вершиною, видимою з 6, є вершина 3. Допишемо її у стек і перей­ демо в неї (мал. 71, б).

Першою видимою вершиною з вершини 3 є вершина 6. Вона не нова, тому перевизначимо індекс поточної вершини 3. Він

8 Р

5 9

-<ЇЗ

7

1

2

3

4

5

6

7

8

2

4

0

5

1

3

0

0

1

1

9

4

9

1

9

9

1

2

3

4

•5

6

7

8

2

4

4

5

1

3

0

0

1

1

9

4

9

1

9

9

а)

б)

Мал. 71

122

a:

 

8 P

K

A.'

•+*:

 

 

&:

 

 

 

 

 

7

 

 

 

 

 

 

 

I

2

3

4

5

6'

7

8

2

4

4

5

1

3

0

0

1

1

3

4

9

1

9

9

1

2

U

4

5

6

7

8

2

4

4

5

1

3

5

0

1

1

3

4

9

1

9

9

6)

Мал. 72

зміниться зі значення 9 на значення 3 (мал. 72, а). Продовжую­ чи перегляд 3-го рядка, ми побачимо нову вершину 7 і допише­ мо її у стек під порядковим номером 5 (мал. 72, б).

Дивлячись з вершини 7, ми спочатку побачимо вже раніше видиму вершину 3. Тому перевизначимо індекс вершини 7 - він дорівнюватиме значенню 4 (мал. 73, а). Продовжуючи пе­ регляд 7-го рядка таблиці суміжності, «зустрінемо» нову вер­ шину 8. Допишемо її у стек під порядковим номером 6 і далі перейдемо до неї (мал. 73, б).

З вершини 8 першою побачимо вершину 3. Оскільки вона бу­ ла відвідана раніше, то можна зробити спробу перевизначити індекс вершини 8. Згідно з нашим алгоритмом тепер він дорів­ нюватиме значенню 4 (мал. 74, а). Чи можна покращити зна-

8

7

3^

І

2

3

4

5

£>*

7

8

6_

І

2

3

4

5

6*

7

8

2

4

4

5

1

3

5

0

_5

2

4

4

5

1

3

5

6

1

1

3

4

9

1

4

9

1

1

3

4

9

1

4

9

б) Мал. 73

123

8

(_

6

I 2 3

4

5

6* 7

S

 

І 2

3

•1

5 6 7 8

 

2

4

4

5

1

3

5

6

 

2

4

4

5

1

3

5

6

 

1

1

3

4

9

1

4

4

 

1

1

3

4

9

1

4

4

a)

Мал.

чення індексу вершини 8, адже ми не завершили перегляд 8-го рядка таблиці суміжності? Ні, оскільки наступна видима вер­ шина з вершини 8 є 7. Однак, хоча її порядковий номер 5 мен­ ший за порядковий номер 6 вершини 8, індекс вершини 8, що вже дорівнює 4, менший за порядковий номер вершини 7.

На цьому перегляд вершин з вершини 8 завершується, і но­ вих вершин нам не трапилося. Це тупик. Повертаємося у стеку до вершини 7 і розглядаємо ребро (7,8). Для того щоб вершина 7 була точкою з'єднання, необхідно, щоб її порядковий номер не перевищував індекс вершини 8 (order7 =% md8 ). Як видно з малюнка 74, б, у нашій ситуації цього не відбувається. Тому можна стверджувати, що ми потрапили в тупик у середині ком­ поненти двозв'язності. У цьому разі можна спробувати перевизначити індекс вершини 7, якщо inds < ind1. У нашому разі ця нерівність не виконується (4 = 4), тому все залишається без змін (мал. 74, б).

Із тупика, що утворився у вершині 7, повертаємося у стеку до вершини 3. Розглядаємо ребро (3,7). Але тепер уже вико­ нується нерівність orderг ^ ind7 (4 ^ 4), тому вершина 3 є точкою з'єднання (мал. 75, а). Повертаємося у вершину 6, що передує вершині 3 у стеку. Ця вершина також тупикова, і тому розгля­ немо ребро (6,3). Для вершин цього ребра стверджується нерівність order^ < indz (3 < 3), тому і вона є точкою з'єднання (мал. 75, б).

Переглядаючи решту ребер, які існують з вершини 6 і мають номери, більші за 3, знайдемо ребро (6,5). Це існуюче ребро могло б поправити значення індексу вершини 6, якби викона­ лася умова (orderb < order6) and (orderh < ind6). Однак другий операнд цього складеного логічного виразу у наглому випадку

124

її.1 8„« а: 8 6 #

к

 

 

 

 

 

 

 

 

к

 

 

 

 

 

ІК

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

8

 

 

 

 

 

 

 

 

8

 

 

 

 

 

 

 

 

" 4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

7

 

 

 

 

 

 

 

 

7

4*

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

З

 

 

 

 

 

 

 

6^

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

І

2 3 4 5 6 7 8

А

/ 2 3 4 5 6' 7 8

1

2

4

4

5

1

3

5

6

 

2

4

4

5

1

3

 

5

6

_5

1

1

3

4

9

1

4

4

 

1

1

3

4

9

1

 

4

4

а)

 

 

 

 

 

 

 

 

б)

 

 

 

 

 

 

 

 

 

Мал. 75

набуває значення false, тому ніяких змін для вершини 6 не відбувається.

У стеку залишилося дві вершини 1 і 5. Логічно, що ми повер­ таємося у вершину 1 і розглядаємо ребро (1,6) (мал. 76, а). Для вершин цього ребра умова orderг =* ind6 не виконується, тому вершина 1 не є точкою з'єднання. Спробуємо скоректувати зна­ чення її індексу. Для цього повинна виконатися умова ind6 < indv Цього не відбувається, оскільки їхні індекси однакові, тому і ніяких змін також немає.

Потрапивши у вершині 1 в тупик, переходимо до вершини 5 і розглядаємо ребро (5,1) з метою визначення, чи не є верши­ на 5 точкою з'єднання. Для цього повинна виконатися умова order5 ^ indv Згідно з малюнком 76, a order5 = 1, ind5 = 1, тобто

1

2

3

4

5

6

7

8

 

1

2

3

4

5

6*

7

8

2

4

4

5

1

3

5

6

LsJ

2

4

4

5

1

3

5

6

1

1

3

4

9

1

4

4

1

1

3

4

1

1

4

4

б)

Мал. 76

125

умова виконується. Однак вершина 5 не є точкою з'єднання, оскільки ребро (5,1) містить стартову вершину, і ми повернули­ ся у неї, пройшовши усі вершини графа (мал. 76, б). Згідно з на­ шим алгоритмом виконується умова (top = 1) and (s = []), а це є умовою завершення алгоритму.

Пояснимо момент завершення алгоритму детальніше. Вико­ нання умови (top = 1) and (s = []) говорить про те, що ми, про­ йшовши всі вершини графа, повернулися у стартову вершину. Проаналізуємо ситуацію, коли стартова вершина є точкою з'єднання. На якому кроці виконання алгоритму ми зможемо це визначити? Для цього звернемося до малюнка 65. Нехай стартовою вершиною буде вершина 6. Скільки разів ми маємо нагоду розглянути цю вершину протягом виконання алгорит­ му? Перший раз, коли ми з неї стартуємо і заходимо у компо­ ненту двозв'язності, що містить вершини 1, 2 та 5. Другий раз - на зворотному шляху, під час переходу до іншої компоненти двозв'язності, що складається із вершин 3, 7 та 8, ми знову пройдемо до вершини 6 і саме в цей момент визначимо, що вона є точкою з'єднання. Таким чином, ми вже побували у вершині 6 двічі і це дало змогу визначити її належність множині точок з'єднання. До речі, слід звернути увагу на те, що в обох цих випад­ ках на поточний момент ще не всі вершини графа були нами пройдені. Отже, при завершенні алгоритму і поверненні у стар­ тову вершину втретє необхідність у перевірці її як точки з'єднан­ ня відпадає. Ознаками цього є те, що порядковий номер верши­ ни стеку дорівнює 1 і всі вершини заданого графа переглянуті.

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

Фрагмент програми, що безпосередньо реалізує алгоритм визначення точок з'єднання у заданому зв'язному графі, може виглядати так:

while (top <> 0) and flag do

{Пошук точок з'єднання виконується,}

begin

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

 

{Визначення вершини графа і, з якої починається}

і := stack[top];

{пошук існуючого ребра.}

repeat

{Пошук вершини/, для якої існує ребро (І,])•}

І inc(j)

 

until (a[i,j]=1) or (j>n);

 

if j > n

{Якщо ребро не знайдено, то це тупик}

then

 

if top > 1

{і якщо ми не знаходимося на початку стеку, то}

126

t h en

 

begin

 

dec(top);

{повертаємося до попередньої вершини у стеку,}

j := і; і := stack[top];

{розглядаємо ребро (/,/),}

if ((orderfi] <= ind[j]) and not ((top = 1) and (s = [])) {і визначаємо}

then write(f_OUt, i, ' ') {умову того, що вершина/є точкою з'єднання.}

else if ind[j] < ind[i]

{Інакше, за потреби,}

then ind[i] := ind[j];

{перевизначаємо її індекс.}

end

 

 

else begin

{Якщо поточна вершина є початком стеку, то визначаємо}

if s = [] then flag := false {умову завершення роботи алгоритму.}

end

 

 

else if order[j] = 0

{Якщо вершина/, для якої існує ребро (/, /), нова,}

then

 

 

begin

 

 

inc(top); stackftop] := j;

{то записуємо її у стек,}

order[j] := top; s := s - [ j ] ; j := 0

{визначаємо її порядковий номер,}

end {коректуємо множину і починаємо пошук інших вершин спочатку.}

else if (order[j] < order[i]) and (order[j] < ind[i]) {Якщо вершина/}

t h e n ind[i] := order[j]

{не нова, то, за потреби,}

end;

 

{коректуємо її індекс.}

Блок програми, що реалізує ініціалізацію всіх початкових значень, повинен бути таким:

for і := 1 to n do begin

order[i] := 0; ind[i] := n + 1

{Початкові значення порядкових номерів}

end;

 

{та індексів вершин графа.}

 

 

{Створення стеку}

top := 1; stack[top] := start; orderfstart] := top;

{із стартової вершини.}

 

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

j := 0; flag := true; s := [1 ..n] - [start]

 

{за винятком стартової.}

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

На малюнку 65 таким мостом є ребро (6,3). Перехід до роз­ гляду алгоритму визначення мостів у заданому зв'язному графі є логічним. Уважно розглянувши зображення графа на малюн­ ку 76, б, ми побачимо, що у результаті виконання алгоритму визначення точок з'єднання ми побудували остовне дерево. Зрозуміло, що всі точки з'єднання належать цьому дереву, а ребро, обидві вершини якого належать множині точок з'єднан­ ня, є мостом. І сам міст також належить остовному дереву!

Алгоритм визначення мостів у графі практично збігається з алгоритмом визначення точок з'єднання. Тому не має потреби детально на ньому зупинятися. Лише наведемо його зміст і відповідну реалізацію мовою програмування.

127

1.Визначити вершину графа start, з якої буде вестися пере­ гляд вершин заданого графа, занести її у стек (top := 1), а поряд­ ковий її номер у масиви order та ind.

2.Якщо стек вичерпано (top = 0), то перейти до п. 12.

3.Визначити вершину і, яка записана у вершині стеку, як поточну.

4.Визначити вершину у, для якої існує ребро (і, у).

5.Якщо не існує ребра (і, у), тобто ми потрапили у тупик, то перейти до п. 8.

6.Якщо вершина у є новою, то записати її у вершину стеку, зробити поточною := у) і перейти до п. 3.

7.Якщо вершина у вже була занесена у стек, тобто не є но­ вою, її порядковий номер у стеку менший, ніж у вершини і, з якої ми у неї дивимося (order[j] < order[i]), і менший, ніж номе­ ри вершин, які ми бачили з вершини і (order[j] < ind[i\), то не­ обхідно перерахувати індекс вершини і як тієї, що побачила відвідану вершину з номером, меншим ніж усі досі видимі з неї

(ind[i] := order[j]). Перейти до п. 4.

8.Якщо у стеку залишився один елемент (top = 1), то пере­ йти до п. 12.

9.Перш ніж зменшити значення вершини стеку на 1 (top := top - 1), необхідно розглянути останні дві вершини і та/, записані у ньому, і ребро (і, у), що їм відповідає.

10.Якщо з вершини у було видно лише вершини, що мають порядкові номери більші, ніж вершина і, тобто всі вони були пройдені під час обходу графа після неї (order[i] <= ind[j]), то ребро (і, у) є мостом. Перейти до п. 3.

11.Якщо з вершини у було видно вершини з меншими по­ рядковими номерами, ніж з вершини і (ind[j] < ind[i]), і між ни­ ми існує ребро (і, у), то це означає, що з вершини і можна діста­ тися цих вершин також. Тому необхідно перевизначити індекс вершини і (ind\i\ := ind\j]) і перейти до п. 3.

12.Завершити алгоритм.

Фрагмент тексту програми буде таким:

while (top <> 0) and flag do begin

:= stack[top]; repeat

| inc(j)

until (a[i,j] = 1) or (j>n); if j > n

then

if top > 1 then begin

dec(top);

j := і; і := stack[top];

if order[i] < ind[j] then writeln(f_out, i, ", j); if ind[j] < ind[i] then ind[i] := ind[j]

end

128

else flag := false else if order[j] = 0

then begin

inc(top); stack[top] :=j; order[j] := top; j := 0 end

else if (orderfj] < top - 1) and (orderfj] < ind[i]) then ind[i] := order[j]

end;

Як бачимо, відмінність визначення мостів від визначення точок з'єднання полягає у більш простих умовах їх існування. Для визначення наявності моста достатньо перевірити лише виконання умови order\ < ind:.

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

Оцінимо обчислювальну складність алгоритму. В основі його лежить пошук у глибину, під час виконання якого робляться коректування значень у масивах order і ind, довжиною п. Тому оцінка ефективності роботи алгоритму визначення точок з'єднання і мостів у графі буде такою самою, як і в алгоритмі пошуку в глибину, тобто 0(п + т).

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

Завдання

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

2.Виконати завдання 1 для графа з кількістю вершин N < 10, в якому є точки з'єднання (хоча б одна) і стартова вершина не є однією з них. Результат виконання програми вивести у файл.

3.Виконати завдання 1 для графа з кількістю вершин N =% 10,

вякому є точки з'єднання (хоча б одна) і одна із них є стар­ товою. Результат виконання програми вивести у файл.

4.Виконати завдання 1 для графа з кількістю вершин N ^ 10,

вякому відсутні точки з'єднання. Результат виконання про­ грами вивести у файл.

5 Інформатика, 9-10 кл.

129

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

6.Розробити та реалізувати у вигляді програми алгоритм ви­

значення мостів у заданому зв'язному графі.

7. Виконати завдання 6 для графа з кількістю вершин N ^ 10, в якому є мости (хоча б один) і стартова вершина не нале­ жить жодному з них. Результат виконання програми вивес­ ти у файл.

8.Виконати завдання 6 для графа з кількістю вершин N ^ 10, в якому є мости (хоча б один) і стартова вершина належить од­ ному з них. Результат виконання програми вивести у файл.

9.Виконати завдання 6 для графа з кількістю вершин N < 10, в якому відсутні мости. Результат виконання програми вивес­ ти у файл.

10.Виконати завдання 7-9 для графа з кількістю вершин N = 100. Результат виконання програми вивести у файл.

У

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

1.Що називається компонентою зв'язності заданого графа?

2.Наведіть і наочно продемонструйте приклади графових задач, для яких є актуальним питання визначення компонент зв'язності заданого графа.

3.Яка вершина графа називається точкою з'єднання? Продемон­ струйте свою відповідь на прикладі.

4.Як називається граф, що містить хоч одну точку з'єднання?

5.Як називається граф, що не містить жодної точки з'єднання?

6.Яка відмінність між компонентою зв'язності і компонентою двозв'язності графа?

7.Наведіть приклади графових задач, де використовується визна­ чення компонент двозв'язності?

8.Яким чином можна застосувати алгоритм пошуку в глибину для визначення точок з'єднання у заданому графі у найпростішому варіанті?

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

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

з'єднання?

12.Сформулюйте алгоритм визначення точок з'єднання у заданому графі.

13.Продемонструйте покрокове виконання алгоритму визначення точок з'єднання у заданому графі на конкретному прикладі.

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

130

15.Запишіть реалізацію алгоритму визначення точок з'єднання за­ даного графа мовою програмування.

16.Які ребра у графі можна назвати мостами? Наведіть приклади.

17.Чому мости у графі мають відношення до його остовного дере­ ва? Обґрунтуйте свою відповідь.

18.Сформулюйте алгоритм визначення точок з'єднання у заданому графі.

19.Продемонструйте покрокове виконання алгоритму визначення

точок з'єднання у заданому графі на конкретному прикладі.

20 Якою є ознака завершення алгоритму визначення точок з'єднання у заданому графі і чому при остаточному поверненні у стартову вершину немає необхідності визначати її належність до множини точок з'єднання?

21Запишіть реалізацію алгоритму визначення точок з'єднання за­ даного графа мовою програмування.

Потоки в мережах

Чи доводилося вам замислюватися над тим, як відбувається розподіл води у міській мережі водопостачання? Зокрема: чи складається мережа із труб однакового діаметра; якщо різного, то чи всі вони максимально заповнені водою; чи є труби, що за­ лишаються порожніми?

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

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

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

,

вихід t

ВХІД^ 10 л 20 л 10 л вихід

В Х І Д ^ 20 л 10 л 20 л

Мал. 77

131

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