Древесная шириной неориентированного графа является очень важным понятием в теории графов. Были изобретены тонны графовых алгоритмов, которые работают быстро, если у вас есть разложение графа с небольшой шириной дерева.
Ширина дерева часто определяется в терминах разложения дерева. Вот график и древовидная декомпозиция этого графа, любезно предоставленная Википедией:
Разложение дерева - это дерево, в котором каждая вершина связана с подмножеством вершин исходного графа со следующими свойствами:
- Каждая вершина в исходном графе находится хотя бы в одном из подмножеств.
- Каждое ребро в исходном графе имеет обе свои вершины хотя бы в одном из подмножеств.
- Все вершины в разложении, подмножества которых содержат данную исходную вершину, связны.
Вы можете проверить, что приведенная выше декомпозиция соответствует этим правилам. Ширина разложения дерева равна размеру его наибольшего подмножества, минус один. Таким образом, это два для вышеупомянутого разложения. Ширина дерева графа является наименьшей шириной любого дерева разложения этого графа.
В этом задании вам будет предоставлен связанный неориентированный граф, и вы должны найти его ширину дерева.
Хотя найти разложение по дереву сложно, существуют другие способы вычисления ширины дерева. На странице Википедии есть больше информации, но один метод вычисления ширины дерева, не упомянутый там, который часто используется в алгоритмах для вычисления ширины дерева, - это минимальная ширина упорядочения исключения. Смотрите здесь для бумаги, используя этот факт.
В порядке исключения удаляются все вершины графа по одному. Когда каждая вершина удаляется, добавляются ребра, соединяющие всех соседей этой вершины друг с другом. Это повторяется до тех пор, пока все вершины не исчезнут. Ширина упорядочения удаления - это наибольшее число соседей, которое имеет любая удаляемая вершина во время этого процесса. Ширина дерева равна минимуму для всех порядков ширины упорядочения исключения. Вот пример программы, использующей этот факт для вычисления ширины дерева:
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
Вы получите график в качестве входных данных, и вы должны вернуть ширину дерева в качестве выходных данных. Формат ввода гибкий. В качестве входных данных вы можете взять список ребер, карту смежности или матрицу смежности. Если вы хотите использовать другой формат ввода, спросите в комментариях. Вы можете предположить, что вход подключен, и вы можете встроить это предположение в свой формат ввода, например, используя список ребер.
РЕДАКТИРОВАТЬ: встроенные операции, которые вычисляют ширину дерева не допускаются. Я извиняюсь за то, что не уточнил это заранее.
Самый короткий код выигрывает.
(V,E)
будет ли это допустимым вводом?