Treewidth z undirected wykresu jest bardzo ważnym pojęciem w teorii grafów. Wynaleziono mnóstwo algorytmów graficznych, które działają szybko, jeśli masz rozkład wykresu o małej szerokości.
Szerokość grzbietu jest często definiowana w kategoriach rozkładu drzew. Oto wykres i rozkład drzewa tego wykresu, dzięki uprzejmości Wikipedii:
Rozkład drzewa to drzewo, w którym każdy wierzchołek jest powiązany z podzbiorem wierzchołków oryginalnego wykresu, o następujących właściwościach:
- Każdy wierzchołek na oryginalnym wykresie znajduje się w co najmniej jednym z podzbiorów.
- Każda krawędź oryginalnego wykresu ma oba wierzchołki w co najmniej jednym z podzbiorów.
- Wszystkie wierzchołki w rozkładzie, których podzbiory zawierają dany oryginalny wierzchołek, są połączone.
Możesz sprawdzić, czy powyższy rozkład podlega tym regułom. Szerokość rozkładu drzewa jest wielkością jego największego podzbioru minus jeden. Dlatego dla powyższego rozkładu są dwa. Szerokość wykresu jest najmniejszą szerokością rozkładu drzewa tego wykresu.
W tym wyzwaniu otrzymasz połączony, nieukierunkowany wykres i musisz znaleźć jego szerokość.
Chociaż znalezienie rozkładu drzew jest trudne, istnieją inne sposoby obliczania szerokości grzbietu. Strona Wikipedii zawiera więcej informacji, ale jedną z metod obliczania szerokości poprzecznej, o której tam nie wspomniano, która jest często stosowana w algorytmach do obliczania szerokości poprzecznej, jest minimalna szerokość zamówienia eliminacji. Zobacz tutaj artykuł wykorzystujący ten fakt.
W kolejności eliminacji eliminuje się wszystkie wierzchołki wykresu pojedynczo. Po wyeliminowaniu każdego wierzchołka dodawane są krawędzie łączące ze sobą wszystkich sąsiadów tego wierzchołka. Jest to powtarzane, aż wszystkie wierzchołki znikną. Szerokość porządkowania eliminacji jest największą liczbą sąsiadów, jaką ma wyeliminowany wierzchołek podczas tego procesu. Szerokość jest równa minimum we wszystkich rzędach szerokości uporządkowania eliminacji. Oto przykładowy program wykorzystujący ten fakt do obliczenia szerokości poprzecznej:
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))
Przykłady:
[(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
Otrzymasz wykres jako dane wejściowe i musisz zwrócić szerokość jako wynik. Format wejściowy jest elastyczny. Jako dane wejściowe możesz wziąć listę krawędzi, mapę przylegania lub macierz przylegania. Jeśli chcesz użyć innego formatu wejściowego, zapytaj w komentarzach. Możesz założyć, że wejście jest podłączone i możesz założyć to założenie do swojego formatu wejściowego, np. Używając listy krawędzi.
EDYCJA: Wbudowane operacje obliczające szerokość profilu są niedozwolone. Przepraszam, że nie sprecyzowałem tego z góry.
Najkrótszy kod wygrywa.
(V,E)
czy byłby to prawidłowy wkład?