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:
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,E)
đây sẽ là một đầu vào hợp lệ?