yarkoslav / diskret_math_project

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Тема проекту: “Аналіз зв'язаності графів”

У цьому проекті реалізована бібліотека, що може використовуватись для аналізу та роботи з графами.

Бібліотека містить наступні функції:

1) Читання графу з файлу

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

2) Запис графу у файл

Граф (заданий у формі словника, описаній в пункті №1 Читання графу з файлу), що передається аргументом функції, записується у файл відповідно до вимог (у такому ж вигляді, як і в даних файлах для тестування програми).

3) Пошук компонент зв'язаності

Функція zvyaznist знаходить компоненти зв'язаності в неорієнтованому графі й повертає список, в якому компоненту зв'язності позначає найменша вершина в ній.

Цей алгоритм базується на пошуку вшир в заданому графі.

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

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

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

У функції був використаний вбудований модуль copy.

4) Пошук компонент сильної зв'язаності

Основна функція - strong_connection, що буде повертати необхідний результат(список із вершин з найменшим індексом для кожної компоненти сильної зв'язаності). Вона використовує в собі 3 функції: make_trasponed_graph, dfs1 та dfs2 make_trasponed_graph - робить для заданого орієнтованого графа його транспоновану версію(граф, у якого всі ребра спрямовані в іншу сторону). Повертає теж граф(у вигляді словника).

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

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

Тепер перейдемо до ідейного опису алгоритму: На першому кроці алгоритму виконується серія обходів вглиб, яка пронизує весь граф. Для цього ми проходимось по всіх вершинах графа і для кожної ще не відвіданої вершини викликаємо обхід вглиб(dfs1). При цьому важливу роль грає час виходу з обходу вглиб кожної вершини - tout[v]. В залежності від зростання цієї величини ми будемо впорядковано додавати наші вершини в order. Введемо позначення: час виходу tout[C] з компоненти C сильної зв'язності визначимо як максимум зі значень tout[v], де v належить С. Наш алгоритм буде на основі такої теореми: Нехай С1 і С2 - дві різні компоненти сильної зв'язності, і нехай в графі конденсації(склеюємо всі вершинки компоненти в одну і ребро між компонентами є тоді й лише тоді, якщо є ребро між якимись вершинками з цих компонент) між ними є ребро (С1, С2). Тоді tout[C1] > tout[C2].

З цієї теореми випливає, що якщо ми відсортуємо всі вершинки v за зменшенням tout[v], то першою виявиться вершинка, яка належить “першій” компоненті, тобто в неї не заходить ребро в графі конденсації. Тепер розглянемо транспонований граф(зроблений за допомогою make_transponed_graph). Неважко зрозуміти, що в цьому графі будуть такі самі компоненти зв'язності. На додаток, граф конденсації для транспонованого графа = транспонованому графу до графа конденсації початкового графа. Це означає, що з “першої” компоненти не будуть виходити ребра нікуди. Таким чином, щоб обійти всю “першу” компоненту зв'язності достатньо просто запустити обхід вглиб з першої вершинки v(dfs2) і продовжувати робити так і далі (для кожної компоненти), поки ми не пройдемо всі вершинки й не отримаємо всі компоненти.

*) Додаткова функція пошуку компонент зв'язаності:

Вона працює за тим же алгоритмом, що й функція №3, проте повертає список словників графів (у такому ж вигляді, як він задається при читанні графу з файлу), кожен з яких є зв'язаним. Дана функція розроблена для оптимізації функцій №5 та №6.

5) Пошук точок сполучення

Основна функція - cutpoints_searching, що буде повертати необхідний результат (список із точок сполучення у графі). Вона використовує в собі функцію find_articulation_points, що працює на основі пошуку в глибину в графі.

Детальніше про функцію find_articulation_points:

Аргументами вона приймає словник, в якому записаний граф, та вершину з якої ми будемо починати пошук в глибину, тому що ми маємо пройтись по всіх компонентах зв'язності. За замовчуванням в стек поміщається введена аргументом вершина, та поки він не пустий ми проходимося по кожній вершині, та вершинах що з нею з'єднані, записуючи їх до множини предків/синів та поміщаючи у чергу і стек, допоки не досягнемо кінця (is_dead_end), очищаючи у такому випадку останній елемент зі стека. Коли стек буде пустим — пошук в глибину буде завершено.

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

Для індексів у отриманому списку за формулою шукаємо вершини, що можуть бути нашим результатом (possible_values), проходячись по словнику графа, та синів, а також знаходимо найнижчий можливий (low), що є мінімальним із possible_values.

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

Ця функція повертає результат у формі списку.

Детальніше про функцію cutpoints_searching:

Сет res стане результатом функції, a components - компоненти зв'язності, отримані із допоміжної функції.

Проходячсь по компонентах зв'язності, ми обираємо будь яку вершину node та присвоюємо змінній result значення функції find_articulation_points, де за аргументи взяті: компонента, яку ми зараз розглядаємо та обрана node. Далі result об'єднується із res.

Вкінці повертається список res - список точок сполучення, що і є результатом програми.

6) Пошук мостів

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

Нехай ми знаходимося в обході в глибину, переглядаючи зараз всі ребра з вершини v. Тоді, якщo поточний ребро (v, to) таке, що з вершини to і з будь-якого її нащадка в дереві обходу в глибину не мають зворотної ребра у вершину v або будь-якого її предка, то це ребро є мостом. В іншому випадку воно мостом не є.

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

Отже, tin[v] - це час заходу пошуку в глибину в вершину v. Тепер введемо список low[v]. Час low[v] дорівнює мінімальному числу з часу заходу в саму вершину tin[v], часів заходу в кожну вершину p, що є кінцем деякого зворотного ребра (v, p), а також з усіх значень low[to] для кожної вершини to, що є безпосереднім сином v в дереві пошуку:

Тоді, з вершини v або її нащадка є зворотне ребро в її предка тоді і тільки тоді, коли знайдеться такий син to, що low [to] <= tin[v].

Таким чином, якщо для поточного ребра (v, to) (що належить дереву пошуку) виконується low[to] > tin[v], то це ребро є мостом; в іншому випадку воно мостом не є.

Якщо знайшли міст — додаємо дане ребро до множини results, яка зберігає у собі усі ребра-мости.

Функцією find_all_bridges ітеруємося по усіх компонентах зв'язності й, за допомогою функції find_bridges, перевіряючи вищезгадані умови, знаходимо мости у конкретній компоненті.

*) Функція тестування всіх функцій

Дана функція читає графи з відповідних файлів та виводить користувачу результати виконання кожної з них.

Розподіл роботи:

Романус Ярослав (yarkoslav) — пошук компонент сильної зв'язаності

Гаврилів Анастасія (be-unkind) — пошук точок сполучення

Пасічник Михайло (fox-flex) — читання графів з файлу та запис їх у файл, тестування програм

Муляк Аліна (alinamuliak) — пошук мостів

Палка Олег (OlehPalka) — пошук компонент зв'язаності

About


Languages

Language:Python 100.0%