Деревна шириною неориентированного графа є дуже важливим поняттям в теорії графів. Винайдено тони алгоритмів графіків, які швидко працюють, якщо розкладається графік з невеликою шириною.
Ширина ширини часто визначається з точки зору розкладу дерев. Ось графік та розкладка дерева цього графіка, люб’язно надано Вікіпедією:
Декомпозиція дерева - це дерево, де кожна вершина асоціюється з підмножиною вершин початкового графа із такими властивостями:
- Кожна вершина в початковому графіку знаходиться щонайменше в одній із підмножин.
- Кожне ребро в початковому графіку має обидві вершини принаймні в одній із підмножин.
- Всі вершини при розкладі, підмножини яких містять задану початкову вершину, з'єднані.
Ви можете перевірити, чи описане вище розкладання відповідає цим правилам. Ширина розкладання дерева - це розмір його найбільшого підмножини, мінус один. Тому для вищезазначеного розкладання це два. Ширина графіка - це найменша ширина будь-якого розкладу дерева цього графіка.
У цьому виклику вам буде надано підключений, непрямий графік, і ви повинні знайти його широку ширину.
Хоча знайти складові дерева важко, існують й інші способи обчислення широти ширини. На сторінці у Вікіпедії є додаткова інформація, але один з методів обчислення пропускної здатності, про який не згадується, який часто використовується в алгоритмах для обчислення широти ширини, є мінімальною шириною замовлення на усунення. Дивіться тут документ, який використовує цей факт.
У порядку елімінації виключаються по черзі всі вершини графа. Коли усувається кожна вершина, додаються ребра, що з'єднують усі сусіди цієї вершини один з одним. Це повторюється, поки всі вершини не зникнуть. Ширина замовлення на елімінацію - це найбільша кількість сусідів, яку має будь-яка вершина, яка видаляється під час цього процесу. Ширина ширини дорівнює мінімуму для всіх замовлень ширини замовлення для усунення. Ось приклад програми, що використовує цей факт для обчислення широти:
import itertools
def elimination_width(graph):
max_neighbors = 0
for i in sorted(set(itertools.chain.from_iterable(graph))):
neighbors = set([a for (a, b) in graph if b == i] + [b for (a, b) in graph if a == i])
max_neighbors = max(len(neighbors), max_neighbors)
graph = [edge for edge in graph if i not in edge] + [(a, b) for a in neighbors for b in neighbors if a < b]
return max_neighbors
def treewidth(graph):
vertices = list(set(itertools.chain.from_iterable(graph)))
min_width = len(vertices)
for permutation in itertools.permutations(vertices):
new_graph = [(permutation[vertices.index(a)], permutation[vertices.index(b)]) for (a, b) in graph]
min_width = min(elimination_width(new_graph), min_width)
return min_width
if __name__ == '__main__':
graph = [('a', 'b'), ('a', 'c'), ('b', 'c'), ('b', 'e'), ('b', 'f'), ('b', 'g'),
('c', 'd'), ('c', 'e'), ('d', 'e'), ('e', 'g'), ('e', 'h'), ('f', 'g'), ('g', 'h')]
print(treewidth(graph))
Приклади:
[(0, 1), (0, 2), (0, 3), (2, 4), (3, 5)]
1
[(0, 1), (0, 2), (1, 2), (1, 4), (1, 5), (1, 6), (2, 3), (2, 4), (3, 4), (4, 6), (4, 7), (5, 6), (6, 7)]
2
[(0, 1), (0, 3), (1, 2), (1, 4), (2, 5), (3, 4), (3, 6), (4, 5), (4, 7), (5, 8), (6, 7), (7, 8)]
3
[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
4
Ви отримаєте графік як вхідний, і ви повинні повернути широку ширину як вихід. Формат введення гнучкий. Ви можете взяти список ребер, карту суміжності або матрицю примикання як вхідні дані. Якщо ви хочете використовувати інший формат введення, запитайте у коментарях. Ви можете припустити, що вхід підключений, і ви можете побудувати це припущення у форматі введення, наприклад, використовуючи список ребер.
EDIT: Вбудовані операції, які обчислюють широту ширини, не дозволяються. Прошу вибачення за те, що не зазначив цього наперед.
Найкоротший код виграє.
(V,E)
чи це буде правильним введенням?