Thuật toán và cấu trúc dữ liệu hiệu quả nhất để duy trì thông tin thành phần được kết nối trên biểu đồ động là gì?


9

Giả sử tôi có một biểu đồ thưa thớt hữu hạn vô hướng và cần có khả năng chạy các truy vấn sau một cách hiệu quả:

  • IsConnected(N1,N2) - trả về nếu có đường dẫn giữa và , nếu không thì FN 1 N 2 FTN1N2F
  • ConnectedNodes(N) - trả về tập hợp các nút có thể truy cập từ N

Điều này được thực hiện dễ dàng bằng cách tính toán trước các thành phần được kết nối của biểu đồ. Cả hai truy vấn có thể chạy trong thời gian O(1) .

Nếu tôi cũng cần có thể thêm các cạnh tùy ý - AddEdge(N1,N2) - thì tôi có thể lưu trữ các thành phần trong cấu trúc dữ liệu tách rời . Bất cứ khi nào một cạnh được thêm vào, nếu nó kết nối hai nút trong các thành phần khác nhau, tôi sẽ hợp nhất các thành phần đó. Điều này thêm chi phí O(1) chi phí AddEdgeO(InverseAckermann(|Nodes|)) cho IsConnectedConnectedNodes (cũng có thể là O(1) ).

Nếu tôi cũng cần có thể loại bỏ các cạnh tùy ý, cấu trúc dữ liệu tốt nhất để xử lý tình huống này là gì? Là một người được biết đến? Tóm lại, cần hỗ trợ các hoạt động sau một cách hiệu quả:

  • IsConnected(N1,N2) - trả về T nếu có một con đường giữa N1N2 , nếu F .
  • ConnectedNodes(N) - trả về tập hợp các nút mà có thể truy cập từ N .
  • AddEdge(N1,N2) - thêm một cạnh giữa hai nút. Lưu ý rằng N1 , N2 hoặc cả hai có thể chưa tồn tại trước đó.
  • RemoveEdge(N1,N2) - xóa cạnh hiện có giữa hai nút.

(Tôi quan tâm đến vấn đề này từ góc độ phát triển trò chơi - vấn đề này dường như xảy ra trong một vài tình huống. Có lẽ người chơi có thể xây dựng đường dây điện và chúng tôi cần biết liệu máy phát có được kết nối với tòa nhà hay không. Có lẽ người chơi có thể khóa và mở khóa cửa, và chúng ta cần biết liệu kẻ thù có thể tiếp cận người chơi hay không. Nhưng đó là một vấn đề rất chung chung, vì vậy tôi đã giải thích nó như vậy)


O ( 1 ) n Ω ( n ) C o n n đ c t đ d N o d e sConnectedNodes không thể chạy trong , vì nếu nó trả về danh sách nút, nó sẽ cần thời gian. Việc triển khai với BFS là tối ưu, do đó, cấu trúc dữ liệu tiềm năng sẽ chỉ cần hỗ trợ IsConnected, AddEdge và RemoveEdge. Điều này có vẻ phù hợp với câu hỏi của bạn: stackoverflow.com/questions/7241151/O(1)nΩ(n)ConnectedNodes
Khăn

@TomvanderZanden Trả lại một bộ đã được xây dựng (trong lập trình, một con trỏ hoặc tham chiếu) là ... mặc dù không có nhiều người dùng có thể làm điều đó và không được bao phủ . C o n n e c t e d N o d e s O ( 1 ) I s C o n n e c t e dO(1)ConnectedNodesO(1)IsConnected
dùng253751

Câu trả lời:


11

Vấn đề này được gọi là kết nối động và nó là một lĩnh vực nghiên cứu tích cực trong cộng đồng khoa học máy tính lý thuyết. Vẫn còn một số vấn đề quan trọng vẫn đang mở ở đây.

Để làm rõ thuật ngữ, bạn yêu cầu kết nối hoàn toàn động vì bạn muốn thêm và xóa các cạnh. Có một kết quả của Holm, de Lichtenberg và Thorup (J.ACM 2001) đạt được thời gian cập nhật và thời gian truy vấn . Từ sự hiểu biết của tôi, nó dường như có thể thực hiện được. Nói một cách đơn giản, cấu trúc dữ liệu duy trì một hệ thống phân cấp của các cây bao trùm - và kết nối động trong các cây dễ dàng hơn. Tôi có thể giới thiệu các ghi chú của Erik D. Demaine để được giải thích rõ ràng tại đây để xem video. Ghi chú của Erik cũng chứa con trỏ đến các kết quả có liên quan khác. Như một lưu ý: tất cả những kết quả này là kết quả lý thuyết.O ( log n / log log n )O(log2n)O(logn/loglogn)

Các cấu trúc dữ liệu này có thể không cung cấp các truy vấn ConnectedNodes mỗi se, nhưng thật dễ dàng để đạt được điều này. Chỉ cần duy trì như một cấu trúc dữ liệu bổ sung cho biểu đồ (ví dụ như danh sách cạnh được kết nối gấp đôi) và thực hiện tìm kiếm theo chiều sâu để có được các nút có thể đạt được từ một nút nhất định.

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.