Treewidth'i hesapla


14

Treewidth bir yönsüz grafik Grafik Teorisi çok önemli bir kavramdır. Grafiğin küçük trewidth ile ayrışması varsa hızlı çalışan tonlarca grafik algoritması icat edilmiştir.

Ağaç genişliği genellikle ağaç ayrışması olarak tanımlanır. İşte Wikipedia'nın izniyle bir grafik ve bu grafiğin ağaç ayrışması:

resim açıklamasını buraya girin

Bir ağaç ayrışması, her bir tepe noktasının, orijinal grafiğin köşe noktalarının bir alt kümesiyle, aşağıdaki özelliklere sahip olduğu bir ağaçtır:

  • Orijinal grafikteki her köşe, alt kümelerden en az birinde bulunur.
  • Orijinal grafikteki her kenar, alt kümelerden en az birinde her iki köşesine sahiptir.
  • Alt kümeleri belirli bir orijinal tepe noktası içeren ayrışmadaki tüm köşeler bağlanır.

Yukarıdaki ayrışmanın bu kurallara uygun olup olmadığını kontrol edebilirsiniz. Bir ağaç ayrışmasının genişliği, eksi bir olan en büyük alt kümesinin boyutudur. Bu nedenle, yukarıdaki ayrışma için iki tanedir. Bir grafiğin üçlü genişliği, o grafiğin herhangi bir ağaç ayrışmasının en küçük genişliğidir.


Bu meydan okumada, size bağlı, yönlendirilmemiş bir grafik verilecek ve bunun trewidth'ini bulmalısınız.

Ağaç ayrışmalarını bulmak zor olsa da, trewidth'i hesaplamanın başka yolları da vardır. Vikipedi sayfasında daha fazla bilgi var, ancak trewidth'i hesaplamak için algoritmalarda sıklıkla kullanılan treewthth'i hesaplamak için bir yöntem minimum eleme sipariş genişliği. Bu gerçeği kullanan bir makale için buraya bakınız .

Eliminasyon düzeninde, bir grafiğin tüm köşeleri teker teker ortadan kaldırılır. Her tepe noktası elimine edildiğinde, bu tepe noktasının tüm komşularını birbirine bağlayan kenarlar eklenir. Bu, tüm köşeler kaybolana kadar tekrarlanır. Eliminasyon sırası genişliği, ortadan kaldırılan herhangi bir tepe noktasının bu işlem sırasında sahip olduğu en fazla komşu sayısıdır. Ağaç genişliği, eleme sırası genişliğinin tüm siparişleri üzerindeki minimum değere eşittir. İşte treewthth hesaplamak için bu gerçeği kullanan bir örnek program:

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

Örnekler:

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

Grafiği girdi olarak alırsınız ve trewidth'i çıktı olarak döndürmeniz gerekir. Giriş formatı esnektir. Girdi olarak kenarların bir listesini, bir bitişiklik haritasını veya bir bitişiklik matrisini alabilirsiniz. Başka bir giriş biçimi kullanmak isterseniz yorumlarda sorun. Girdinin bağlı olduğunu varsayabilir ve bu varsayımı girdi biçiminize, örneğin bir kenar listesi kullanarak oluşturabilirsiniz.

DÜZENLEME: Ağaç genişliğini hesaplayan yerleşik işlemlere izin verilmez. Bunu önceden belirtmediğim için özür dilerim.

En kısa kod kazanır.


Bir grafik resmi olarak bir demet olduğu için (V,E)bu geçerli bir girdi olur mu?
ბიმო

@Bruce_Forte Kesinlikle.
isaacg

Yanıtlar:


7

Oktav, 195 bayt

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

Bir bitişiklik matrisi girdi olarak alan bir işlev. Büyük miktarda bellek tüketir, bu nedenle köşe sayısının 10-12'den fazla olması işe yaramaz.

  • endfunctionancak tio'ya eklenmesine gerek yoktur .

Çevrimiçi deneyin!

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 bayt rekabet etmeyen *

lambda L:Graph(L).treewidth()

* Bu cevap OP'nin "Builtins yasaklandı" sorusunu değiştirmeden önce gönderdi, bu yüzden onu rakipsiz yaptı.

Çevrimiçi Demo!


1
Whelp. Bu sönük. Maalesef, yerleşikleri yasaklamak zorunda kalacağım, bunun için üzgünüm.
isaacg

@isaacg Sorun değil. Elimde başka bir şey daha var :)
rahnema1

@isaacg bu cevap standart bir boşluk açmıyor mu?
PyRulez

rahnema1, benim düzenlememe bakın. Yerleşik yapıların yasaklanması nedeniyle bu yanıta izin verilmez. Lütfen silin veya
rakipsiz

@isaacg Teşekkürler, rakipsiz olarak işaretledim.
rahnema1

5

Haskell (Lambdabot), 329 321 245 bayt

İşte benim çözümüm, girdinin esnekliği sayesinde, herhangi bir örneği içeren grafiklerle grafikler üzerinde çalışıyor 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

Çevrimiçi deneyin!

Ungolfed sürümü:

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))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.