Course_manual - Стор 2
// функція виявлення не пройдених вершин графа void WayDepth (void)
// Глобальна змінна для обчислення індексу
// у масивах T і B
// Глобальна змінна для обчислення міток
for (u = 0; u // спочатку всі вершини графа
// помічаємо як не пройдені
for (u = 0; u // вибір черговий не пройденої
if (Mark[u] = = Depth (u,
void main ( void )
File *p, *f; int i, j, n;
// Введення вихідних даних
p = fopen( "spisok_Adj.in", "r"); if (fscanf (p, “%d”, &n) != EOF)
// встановлення покажчика початку списку суміжності для
// введення мітки вершини // введення числа вершин у списку // суміжності вершини i
for (j = 0; j введення списку суміжності вершини i
Fst[i+1] = Fst[i] + Nbr[i]; // встановлення покажчика початку
// Список суміжності наступної вершини
// Прохід графа у глибину
f = fopen( "spisok_reber.out", "w"); for (i = 0; i, представленого на рис. 1.4. У графі 7 вершин, вершини позначені цілими числами від 0 до 6).
Структура суміжності цього графа:
Вихідні дані структури суміжності графа задаються у текстовому файлі spisok_Adj.in у наступному форматі:
• у першому рядку файлу міститься число вершин графа;
• далі для кожної вершини в окремому рядку вказується номер самої вершини, число вершин суміжних з даною, і список цих вершин (вершини перераховуються в порядку зростання міток вершин).
Вихідний файл для графа на рис. 1.4.: 7
У програмі ця структура реалізована в масивах Vt, ADj, Fst, Nbr, що мають такий вигляд:
Дане відображення структури суміжності дозволяє звертатися до елементів масивів за номерами (позначками) відповідних вершин.Операція v ADj [x] у програмній реалізації представляється як
for (i = 0; i де Nbr[x] – кількість вершин у структурі суміжності для вершини x; Adj [x] – масив , що містить списки суміжності для кожної вершини ; Fst [x] – номер першої вершини у списку суміжності , що відповідає вершині x, тоді Fst [x] + i – номер i – й вершини у списку суміжності , що відповідає вершині x. Наприклад, нехай x = 3, тоді
Nbr [3] = 2 ( у списку суміжності вершини x два елементи ),
Adj [Fst [3] + 0] = Adj [10] = 1 і Adj [Fst [3] + 1] = Adj
[11] = 2 становлять список суміжності вершини x = 3.
Розв'язання задачі починається з виклику функції WayDepth, яка спочатку позначає в масиві Mark всі вершини як не пройдені (фарбує їх міткою рівною). для неї запускається функція Depth, що реалізує прохід графа в глибину Функція Depth позначає в масиві Mark цю вершину як виявлену (фарбує її значенням цілої змінної count, тобто пройдені вершини поступово нумеруються від 0 до │ V │ їх потрапляємо ).Затем проглядається список суміжності вершини , для якої запущена функція Depth.Якщо в цьому списку є ще не пройдені вершини (т. е. мітка Mark [v] вершини v дорівнює то ребро (x, v) додається до безлічі основних ребер дерева пошуку в глибину (вершини x і v поміщаються в масив T) Процес проходу графа в глибину в цьому випадку триває, починаючи з не пройденої вершини v (для вершини v запускається функція Depth). Коли у списку суміжності вершини x виявлена пройдена вершина, то при Mark [v] ≠ ребро (x, v) буде зворотним ребром, якщо Mark [v] іv ≠ s. Умова Mark [v] означає, що вершина v була пройдена раніше
вершини x. Тому ребро (x, v) буде оберненим, якщо воно не є ребром дерева пошуку, пройденим від предка s до x, т. е. v ≠ s.
Дерево пошуку у глибину для графа на рис. 1.4. має такий вигляд:
Суцільними лініями відзначені ребра дерева, які були пройдені під час обходу графа в глибину, пунктирними – ребра назад. (На рис. 1.4. жирними лініями відзначені ребра, які були пройдені під час обходу графа в глибину).
Стан робочих масивів Mark, T і B після завершення алгоритму наведено нижче:
Результати роботи виводяться у файл spisok_reber.out у наступному форматі:
• у першому рядку файлу мітки початкових вершин ребер дерева пошуку в глибину;
• у другому рядку файлу мітки кінцевих вершин ребер дерева пошуку в глибину;
• у третьому рядку файлу ознаки ребер: значення 1 – ознака основного ребра, значення 0 – ознака зворотного ребра.
Вихідний файл для графа на рис. 1.4.:
0 1 2 2 3 2 4 4 5 6
1 2 0 3 1 4 0 5 6 4
1 1 0 1 0 1 0 1 1 0
Завдання 2 . У неорієнтованому графі G(V,E) потрібно виділити компоненти зв'язності.
Оскільки граф неорієнтований, то знаходження компонент зв'язності досить пройти граф в глибину, поки залишаються не пройдені вершини, у своїй позначаючи вершини однієї компоненти зв'язності однаковими мітками. І тому досить використовувати змінну , значення якої змінюється , якщо повністю пройдено компонента зв'язності ( у цій програмі це глобальна змінна count). Компонент зв'язності при проході в глибину буде повністю пройдений, коли в списках суміжності вершин цієї компоненти не буде не пройдених вершин. Вершиниграфа позначені цілими числами. Граф заданий структурою суміжності Adj [u].
Програма виділення компонентів зв'язності – пошук у глибину ( мова Сі )
# define maxn 100 // максимальна кількість вершин у графі
# define maxADj 1000 // максимальна довжина списку суміжності графа
int Adj [maxADj]; // Список суміжності графа
// покажчики на списки суміжності кожної v V
// число вершин у списку суміжності кожної v V
// Список вершин графа
// Мітки вершин графа
// функція проходження однієї компоненти зв'язності
void Component (int u)
// вершина u позначається як пройдена вершина
// Вибір зі списку суміжності u ще не
// функція пошуку не пройдених вершин графа, т.к. е. нової компоненти зв'язності STRONGL_Comp2 (void)
for (u = 0; u // спочатку всі вершини графа
// помічаємо як не пройдені
for (u = 0; u // вибір чергової не пройденої вершини
// Збільшення числа компонент зв'язності
void main ( void )
// Введення вихідних даних
p = fopen( "spisok_Adj.in", "r");
if (fscanf (p, “%d”, &n) != EOF)
// Введення числа вершин графа
// встановлення покажчика початку списку суміжності для
for (i = 0; i // введення мітки вершини
// Введення числа вершин у списку
// суміжності вершини i
for (j = 0; j // введення списку суміжності вершини i
Fst[i+1] = Fst[i] + Nbr[i];
// встановлення покажчика початку
// Список суміжності наступної вершини
STRONGL_Comp2 ( ); // Прохід графа в глибину, пошук компонент зв'язності
f = fopen( "component.out", "w"); for ( i = 0; i , представленого на рис. 1.5. У графі 11 вершин , вершини позначені цілими числами , починаючи з1.
Структура суміжності цього графа:
Вихідні дані структури суміжності графа задаються у текстовому файлі spisok_Adj.in у аналогічному форматі задачі 1.
Вихідний файл для графа на рис. 1.5.:
У програмі ця структура реалізована у масивах Vt, ADj, Fst, Nbr, мітки компонент – у масиві Mark. Стан масивів після виконання програми наведено нижче.
Результати роботи виводяться у файл component.out у наступному форматі:
• у першому рядку файлу мітки вершин графа;
• у другому рядку файлу номера компонент зв'язку. Вихідний файл для графа на рис. 1.5.:
2.3.3. Обхід (або пошук) завширшки
Нехай заданий граф (вихідний граф може бути неорієнтованим або орієнтованим) і фіксована початкова вершина s. У процесі пошуку ми йдемо вшир, а не вглиб: спочатку переглядаємо всі сусідні з вершини, потім сусідів сусідів і т.д. д. Алгоритм пошуку в ширину перераховує всі досяжні з s (якщо йти по ребрах) вершини в порядку зростання відстані від s. Відстанню вважається довжина (число ребер) найкоротшого шляху. У процесі пошуку з графа виділяється частина, звана "деревом пошуку завширшки" з коренем s. Воно містить усі досяжні з s вершини (і тільки їх). Для кожної з цих вершин шлях з кореня (вершини s) у дереві пошуку буде одним із найкоротших шляхів (з початкової вершини) у графі. Алгоритм також використовує кольори вершин. Спочатку всі вершини білі (не пройдені), у процесі пошуку біла вершина може стати сірою, якщо вона виявлена, а сіра – чорною. Відмінність між сірою та чорною вершиною дозволяє підтримувати таку властивість: якщо (u,v) E та u чорна, то v – сіра або чорна вершина. Таким чином, тільки сірі вершини можуть мати суміжні невиявленівершини.
Спочатку дерево пошуку завширшки складається тільки з кореня - початкової вершини s. Як тільки виявлена біла вершина v, суміжна з раніше знайденою вершиною u, вершина v (разом з ребром (u,v)) додається до дерева пошуку, стаючи нащадком вершини u, а u стає батьком v. Кожна вершина виявляється лише одного разу, тож двох батьків у неї бути не може.
Нижче наведений алгоритм використовує представлення графа списками суміжних вершин Adj [u]. Для кожної вершини u графа додатково зберігаються її колір Mark [u] та її попередник Pr[u]. Якщо попередника немає (наприклад, якщо u = s або u ще не виявлено), то Pr [u] = nil. Крім того, d [u] записується відстань від s до u. Алгоритм також використовує чергу Q для зберігання безлічі сірих вершин.