트리 폭 계산


14

무 방향 그래프 의 트리 폭 은 그래프 이론에서 매우 중요한 개념입니다. 트리 폭이 작은 그래프를 분해하면 빠르게 실행되는 수많은 그래프 알고리즘이 발명되었습니다.

트리 폭은 종종 트리 분해로 정의됩니다. 다음은 Wikipedia에서 제공 한 그래프와 그 그래프의 트리 분해입니다.

여기에 이미지 설명을 입력하십시오

트리 분해는 다음과 같은 속성을 사용하여 각 정점이 원래 그래프의 정점의 하위 집합과 연결되는 트리입니다.

  • 원본 그래프의 모든 정점은 하나 이상의 하위 집합에 있습니다.
  • 원본 그래프의 모든 모서리에는 하나 이상의 하위 집합에 정점이 모두 있습니다.
  • 주어진 원본 정점이 포함 된 부분 집합이있는 분해의 모든 정점이 연결됩니다.

위의 분해가이 규칙을 따르는 지 확인할 수 있습니다. 트리 분해의 너비는 가장 큰 부분 집합의 크기에서 1을 뺀 크기입니다. 따라서, 상기 분해의 경우 2 개이다. 그래프의 트리 폭은 해당 그래프의 트리 분해에서 가장 작은 폭입니다.


이 도전에서, 당신은 연결된 무 방향 그래프를 받게 될 것이고, 당신은 그것의 treewidth를 찾아야합니다.

트리 분해를 찾기는 어렵지만 트리 폭을 계산하는 다른 방법이 있습니다. Wikipedia 페이지에는 더 많은 정보가 있지만 트리 폭을 계산하기 위해 알고리즘에서 자주 사용되는 트리 폭을 계산하는 한 가지 방법은 최소 제거 순서 폭입니다. 이 사실을 사용한 논문 은 여기 를 참조 하십시오 .

제거 순서에서 한 번에 하나씩 그래프의 모든 정점을 제거합니다. 각 정점이 제거되면 해당 정점의 모든 이웃을 서로 연결하는 가장자리가 추가됩니다. 모든 정점이 사라질 때까지이 과정이 반복됩니다. 제거 순서 폭은 제거되는 정점이이 프로세스 동안 갖는 최대 이웃 수입니다. 트리 폭은 모든 제거 순서 폭의 순서에 대한 최소값과 같습니다. 다음은이 사실을 사용하여 트리 폭을 계산하는 예제 프로그램입니다.

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)이것이 유효한 입력입니까?
ბიმო

@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그러나 tio에 추가해야 할 필요는 없습니다 .

온라인으로 사용해보십시오!

언 골프 드 :

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

*이 답변은 OP가 "Builtins are 금지"라는 질문을 변경하기 전에 게시되었으므로 비경쟁으로 만들었습니다.

온라인 데모!


1
강아지. 고무적이지 않습니다. 불행히도, 나는 내장을 금지해야 할 것입니다. 죄송합니다.
isaacg

@isaacg 문제 없습니다. 나는 내 손에 또 다른 것이 있다 :)
rahnema1

@isaacg이 답변이 표준 허점을 위반하지 않습니까?
PyRulez

rahnema1, 내 편집을 참조하십시오. 내장은 금지되어 있으므로이 답변은 허용되지 않습니다. 삭제하거나 비경쟁으로 표시
isaacg

@isaacg 감사합니다. 경쟁이 아닌 것으로 표시했습니다.
rahnema1

5

하스켈 (Lambdabot), 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))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.