Calcola larghezza dell'albero


14

La larghezza dell'albero di un grafico non orientato è un concetto molto importante nella teoria dei grafi. Sono state inventate tonnellate di algoritmi grafici che funzionano velocemente se si dispone di una decomposizione del grafico con una piccola larghezza dell'albero.

La larghezza degli alberi è spesso definita in termini di decomposizioni degli alberi. Ecco un grafico e una scomposizione dell'albero di quel grafico, per gentile concessione di Wikipedia:

inserisci qui la descrizione dell'immagine

Una decomposizione dell'albero è un albero in cui ogni vertice è associato a un sottoinsieme dei vertici del grafico originale, con le seguenti proprietà:

  • Ogni vertice nel grafico originale si trova in almeno uno dei sottoinsiemi.
  • Ogni bordo nel grafico originale ha entrambi i suoi vertici in almeno uno dei sottoinsiemi.
  • Tutti i vertici nella decomposizione i cui sottoinsiemi contengono un dato vertice originale sono collegati.

Puoi verificare che la decomposizione sopra segua queste regole. La larghezza di una decomposizione dell'albero è la dimensione del suo sottoinsieme più grande, meno uno. Pertanto, è due per la decomposizione sopra. La larghezza dell'albero di un grafico è la larghezza più piccola di qualsiasi decomposizione dell'albero di quel grafico.


In questa sfida, ti verrà dato un grafico connesso e non orientato e dovrai trovare la sua larghezza dell'albero.

Mentre trovare le decomposizioni degli alberi è difficile, ci sono altri modi per calcolare la larghezza degli alberi. La pagina di Wikipedia ha più informazioni, ma un metodo di calcolo della larghezza dell'albero non menzionato qui che viene spesso utilizzato negli algoritmi per calcolare la larghezza dell'albero è la larghezza minima di ordinazione di eliminazione. Vedi qui per un documento che utilizza questo fatto.

In un ordine di eliminazione, si eliminano tutti i vertici di un grafico uno alla volta. Quando ogni vertice viene eliminato, i bordi vengono aggiunti collegando tutti i vicini di quel vertice tra loro. Questo si ripete fino a quando tutti i vertici non sono spariti. La larghezza dell'ordine di eliminazione è il maggior numero di vicini che qualsiasi vertice che viene eliminato ha durante questo processo. La larghezza dell'albero è uguale al minimo su tutti gli ordini della larghezza degli ordini di eliminazione. Ecco un programma di esempio che utilizza questo fatto per calcolare la larghezza dell'albero:

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))

Esempi:

[(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

Riceverai il grafico come input e dovrai restituire la larghezza dell'albero come output. Il formato di input è flessibile. È possibile prendere un elenco di spigoli, una mappa di adiacenza o una matrice di adiacenza come input. Se desideri utilizzare un altro formato di input, chiedi nei commenti. È possibile supporre che l'input sia collegato e che tale assunzione possa essere incorporata nel formato di input, ad esempio utilizzando un elenco di spigoli.

EDIT: le operazioni integrate che calcolano la larghezza dell'albero non sono consentite. Mi scuso per non aver specificato questo in anticipo.

Il codice più corto vince.


Dato che un grafico è formalmente una tupla (V,E), questo sarebbe un input valido?
ბიმო

@Bruce_Forte Assolutamente.
Isaacg,

Risposte:


7

Ottava, 195 byte

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

Una funzione che accetta come input una matrice di adiacenza. Consuma una grande quantità di memoria, quindi è inutile se il numero di vertici è superiore a 10-12.

  • non è necessario endfunctiontuttavia dovrebbe essere aggiunto a tio.

Provalo online!

Ungolfed:

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 byte non competitivi *

lambda L:Graph(L).treewidth()

* Questa risposta è stata pubblicata prima che OP cambiasse la domanda che "I builtin sono stati vietati", quindi l'ho reso non competitivo.

Demo online!


1
Cucciolo. Non è interessante. Sfortunatamente, dovrò vietare i builtin, mi dispiace per quello.
Isaacg,

@isaacg Nessun problema. Ho un'altra cosa in mano :)
rahnema1,

@isaacg questa risposta non viola una scappatoia standard?
PyRulez,

rahnema1, guarda la mia modifica. I builtin sono vietati, quindi questa risposta non è consentita. Si prega di eliminarlo o contrassegnarlo come non competitivo
isaacg

@isaacg Grazie, l'ho contrassegnato come non competitivo.
rahnema1

5

Haskell (Lambdabot), 329 321 245 byte

Ecco la mia soluzione, grazie alla flessibilità dell'input funziona su grafici con grafici contenenti qualsiasi tipo di istanza di 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

Provalo online!

Versione non golfata:

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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.