Bạn có thể sử dụng một set
(theo nghĩa toán học của từ này, tức là một bộ sưu tập không thể chứa các bản sao) để lưu trữ các trạng thái mà bạn đã thấy. Các hoạt động bạn sẽ cần để có thể thực hiện trên này là:
- yếu tố chèn
- kiểm tra nếu các yếu tố đã có trong đó
Khá nhiều ngôn ngữ lập trình nên đã có hỗ trợ cho cấu trúc dữ liệu có thể thực hiện cả hai thao tác này trong thời gian không đổi ( ). Ví dụ:O(1)
set
trong Python
HashSet
trong Java
Thoạt nhìn, có vẻ như việc thêm tất cả các trạng thái bạn từng thấy vào một tập hợp như thế này sẽ rất tốn kém về trí nhớ, nhưng nó không quá tệ so với bộ nhớ bạn cần cho biên giới của bạn; nếu hệ số phân nhánh của bạn là , biên giới của bạn sẽ tăng thêm b - 1 phần tử cho mỗi nút mà bạn truy cập (xóa 1 nút khỏi biên giới để "truy cập" nó, thêm b người kế thừa / con mới), trong khi đó, bộ của bạn sẽ chỉ tăng thêm 1 nút trên mỗi nút truy cập.bb−11b1
Trong mã giả, một bộ như vậy (hãy đặt tên cho nó closed_set
, để phù hợp với mã giả trên wikipedia có thể được sử dụng trong Tìm kiếm đầu tiên theo chiều rộng như sau:
frontier = First-In-First-Out Queue
frontier.add(initial_state)
closed_set = set()
while frontier not empty:
current = frontier.remove_next()
if current == goal_state:
return something
for each child in current.generate_children()
if child not in closed_set: // This operation should be supported in O(1) time regardless of closed_set's current size
frontier.add(child)
closed_set.add(current) // this should also run in O(1) time
(một số biến thể của mã giả này cũng có thể hoạt động và hiệu quả hơn hoặc ít hơn tùy thuộc vào tình huống; ví dụ: bạn cũng có thể lấy closed_set
tất cả các nút mà bạn đã thêm trẻ em vào biên giới, và sau đó hoàn toàn tránh generate_children()
cuộc gọi nếu current
đã có trong closed_set
.)
Những gì tôi mô tả ở trên sẽ là cách tiêu chuẩn để xử lý vấn đề này. Theo trực giác, tôi nghi ngờ một "giải pháp" khác có thể là luôn luôn ngẫu nhiên hóa thứ tự của một danh sách mới của các quốc gia kế nhiệm trước khi thêm chúng vào biên giới. Bằng cách này, bạn không tránh khỏi vấn đề thỉnh thoảng thêm các trạng thái mà trước đó bạn đã mở rộng ra biên giới, nhưng tôi nghĩ rằng nó sẽ làm giảm đáng kể nguy cơ bị mắc kẹt trong các chu kỳ vô hạn.
Hãy cẩn thận : Tôi không biết bất kỳ phân tích chính thức nào về giải pháp này chứng tỏ rằng nó luôn luôn tránh các chu kỳ vô hạn. Nếu tôi cố gắng "chạy" cái này qua đầu, bằng trực giác, tôi nghi ngờ nó nên hoạt động tốt và nó không cần thêm bộ nhớ. Có thể có những trường hợp cạnh mà tôi không nghĩ đến ngay bây giờ, vì vậy nó cũng đơn giản là không hoạt động, giải pháp tiêu chuẩn được mô tả ở trên sẽ là đặt cược an toàn hơn (với chi phí bộ nhớ nhiều hơn).