Обчисліть ширину ширини


14

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

Ширина ширини часто визначається з точки зору розкладу дерев. Ось графік та розкладка дерева цього графіка, люб’язно надано Вікіпедією:

введіть тут опис зображення

Декомпозиція дерева - це дерево, де кожна вершина асоціюється з підмножиною вершин початкового графа із такими властивостями:

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

Ви можете перевірити, чи описане вище розкладання відповідає цим правилам. Ширина розкладання дерева - це розмір його найбільшого підмножини, мінус один. Тому для вищезазначеного розкладання це два. Ширина графіка - це найменша ширина будь-якого розкладу дерева цього графіка.


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

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

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

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)чи це буде правильним введенням?
ბიმო

@Bruce_Forte Абсолютно.
isaacg

Відповіді:


7

Октава, 195 байт

function x=F(a)r=rows(a);P=perms(s=1:r);x=r;for m=s;b=a;n=0;for z=P(m,:);(T=sum(b)(z))&&{b|=(k=accumarray(nchoosek(find(b(z,:)),2),1,[r r]))|k';n=max(T,n);b(z,:)=0;b(:,z)=0}{4};end;x=min(x,n);end

Функція, яка приймає за вхід матрицю суміжності. Він споживає велику кількість пам'яті, тому марно, якщо кількість вершин перевищує 10-12.

  • немає необхідності, endfunctionоднак його слід додавати до тіо.

Спробуйте в Інтернеті!

Безголівки:

function min_width = treewidth(graph_adj)
    Nvertices = rows(graph_adj)
    Permutations = perms(1:Nvertices);                                                            % do not try it for large number of vertices
    min_width = Nvertices;
    for v = 1:Nvertices;
        new_graph=graph_adj;
        max_neighbors=0;
        for p = Permutations(v,:)
            Nneighbors=sum(new_graph)(p);
            if(Nneighbors)>0
                connection=accumarray(nchoosek(find(new_graph(p,:)),2),1,[Nvertices Nvertices]);  % connect all neighbors
                new_graph|=connection|connection';                                                % make the adjacency matrix symmetric
                new_graph(p,:)=0;new_graph(:,p)=0;                                                % eliminate the vertex
                max_neighbors=max(Nneighbors,max_neighbors);
            end
        end
        min_width=min(min_width,max_neighbors);
    end
end

5

SageMath, 29 байт без конкуренції *

lambda L:Graph(L).treewidth()

* Ця відповідь була розміщена перед зміною ОП питання про те, що "Будівництво заборонено", тому я зробив це неконкурентним.

Інтернет-демонстрація!


1
Whelp. Це не надихає. На жаль, мені доведеться заборонити вбудовані, пробачте про це.
isaacg

@isaacg Немає проблем. У мене в руках ще одна річ :)
rahnema1

@isaacg ця відповідь не порушує стандартну лазівку?
PyRulez

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

@isaacg Дякую, я позначив це як неконкурентоспроможне.
rahnema1

5

Хаскелл (Ламбдабот), 329 321 245 байт

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

(&)=elem
l=length
t n g s=last$minimum[max(t n g b)$t(n++b)g$s\\b|b<-filterM(\_->[0>1,1>0])s,l b==div(l s)2]:[l[d|d<-fst g,not$d&n,d/=s!!0,(d&)$foldr(\x y->last$y:[x++y|any(&y)x])[s!!0]$join(>>)[e|e<-snd g,all(&(s!!0:d:n))e]]|1==l s]
w=t[]<*>fst

Спробуйте в Інтернеті!

Негольована версія:

type Vertex a = a
type Edge a   = [Vertex a]
type Graph a  = ([Vertex a],[Edge a])

vertices = fst
edges = snd

-- This corresponds to the function w
treeWidth :: (Eq a) => Graph a -> Int
treeWidth g = recTreeWidth g [] (vertices g)

-- This is the base case (length s == 1) of t
recTreeWidth graph left [v] =
    length [ w | w <- vertices graph
               , w `notElem` left
               , w /= v
               , w `elem` reachable (subGraph w)
           ]

  where subGraph w = [ e | e <- edges graph, all (`elem` v:w:left) e ]

        reachable g = foldr accumulateReachable [v] (g>>g)
        accumulateReachable x y = if any (`elem` y) x
                                  then x++y
                                  else y

-- This is the other case of t
recTreeWidth graph left sub =
  minimum [ comp sub' | sub' <- filterM (const [False,True]) sub
                      , length sub' == div (length sub) 2
          ]

  where comp b = max (recTreeWidth graph left b)
                     (recTreeWidth graph (left++b) (sub\\b))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.