Tính toán băng thông


14

Các treewidth của một đồ thị vô hướng là một khái niệm rất quan trọng trong Lý thuyết đồ thị. Hàng tấn thuật toán đồ thị đã được phát minh để chạy nhanh nếu bạn có sự phân tách đồ thị với treewidth nhỏ.

Treewidth thường được định nghĩa dưới dạng phân hủy cây. Đây là một biểu đồ và sự phân rã cây của biểu đồ đó, theo lịch sử của Wikipedia:

nhập mô tả hình ảnh ở đây

Phân rã cây là một cây trong đó mỗi đỉnh được liên kết với một tập hợp con của các đỉnh của đồ thị ban đầu, với các thuộc tính sau:

  • Mỗi đỉnh trong biểu đồ gốc nằm trong ít nhất một trong các tập con.
  • Mỗi cạnh trong biểu đồ gốc có cả hai đỉnh của nó trong ít nhất một trong các tập con.
  • Tất cả các đỉnh trong phân tách có tập con chứa một đỉnh ban đầu đã cho được kết nối.

Bạn có thể kiểm tra phân tách ở trên tuân theo các quy tắc này. Chiều rộng của phân rã cây là kích thước của tập hợp con lớn nhất của nó, trừ đi một. Do đó, nó là hai cho sự phân hủy ở trên. Treewidth của đồ thị là chiều rộng nhỏ nhất của bất kỳ sự phân rã cây nào của đồ thị đó.


Trong thử thách này, bạn sẽ được cung cấp một biểu đồ được kết nối, không bị chặn và bạn phải tìm treewidth của nó.

Mặc dù việc tìm kiếm sự phân hủy của cây rất khó khăn, nhưng có nhiều cách khác để tính toán treewidth. Trang Wikipedia có nhiều thông tin hơn, nhưng một phương pháp tính toán treewidth không được đề cập ở đó thường được sử dụng trong các thuật toán để tính toán treewidth là chiều rộng thứ tự loại bỏ tối thiểu. Xem ở đây cho một bài báo sử dụng thực tế này.

Trong một thứ tự loại bỏ, người ta loại bỏ tất cả các đỉnh của đồ thị một lần. Khi mỗi đỉnh được loại bỏ, các cạnh được thêm vào kết nối tất cả các lân cận của đỉnh đó với nhau. Điều này được lặp lại cho đến khi tất cả các đỉnh biến mất. Chiều rộng thứ tự loại bỏ là số lượng lân cận lớn nhất mà bất kỳ đỉnh nào đang bị loại bỏ trong quá trình này. Treewidth bằng với mức tối thiểu trên tất cả các thứ tự của chiều rộng thứ tự loại bỏ. Dưới đây là một chương trình ví dụ sử dụng thực tế này để tính toán treewidth:

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

Ví dụ:

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

Bạn sẽ nhận được biểu đồ làm đầu vào và bạn phải trả lại treewidth làm đầu ra. Các định dạng đầu vào là linh hoạt. Bạn có thể lấy danh sách các cạnh, bản đồ kề hoặc ma trận kề là đầu vào. Nếu bạn muốn sử dụng định dạng đầu vào khác, hãy hỏi trong các nhận xét. Bạn có thể giả sử đầu vào được kết nối và bạn có thể xây dựng giả định đó thành định dạng đầu vào của mình, ví dụ: bằng cách sử dụng danh sách các cạnh.

EDIT: Các hoạt động tích hợp tính toán treewidth không được phép. Tôi xin lỗi vì đã không chỉ định trước.

Mã ngắn nhất sẽ thắng.


Vì một biểu đồ chính thức là một tuple, (V,E)đây sẽ là một đầu vào hợp lệ?
ბიმო

@Bruce_Forte Hoàn toàn.
isaacg

Câu trả lời:


7

Octave, 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

Một hàm lấy đầu vào là ma trận kề. Nó tiêu thụ một lượng lớn bộ nhớ nên sẽ vô dụng nếu số lượng đỉnh lớn hơn 10-12.

  • không có nhu cầu endfunctiontuy nhiên nó nên được thêm vào tio.

Hãy thử trực tuyến!

Ung dung:

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 không biên dịch *

lambda L:Graph(L).treewidth()

* Câu trả lời này được đăng trước khi OP thay đổi câu hỏi rằng "Nội dung bị cấm", vì vậy tôi đã nghiền ngẫm nó.

Demo trực tuyến!


1
Whelp. Đó là không mệt mỏi. Thật không may, tôi sẽ phải cấm các nội dung, xin lỗi về điều đó.
isaacg

@isaacg Không sao. Tôi có một thứ khác trong tay :)
rahnema1

@isaacg không câu trả lời này vi phạm một lỗ hổng tiêu chuẩn?
PyRulez

rahnema1, xem chỉnh sửa của tôi. Nội dung bị cấm, vì vậy câu trả lời này không được phép. Vui lòng xóa nó hoặc đánh dấu nó là không
lọc

@isaacg Cảm ơn, tôi đã đánh dấu nó là không soạn thảo.
rahnema1

5

Haskell (Lambdabot), 329 321 245 byte

Đây là giải pháp của tôi, nhờ vào tính linh hoạt của đầu vào, nó hoạt động trên các biểu đồ với các biểu đồ có chứa bất kỳ loại nào là một thể hiện của 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

Hãy thử trực tuyến!

Phiên bản bị đánh cắp:

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))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.