Możesz użyć set
(w matematycznym znaczeniu tego słowa, tj. Kolekcji, która nie może zawierać duplikatów) do przechowywania stanów, które już widziałeś. Operacje, które musisz wykonać, to:
- wstawianie elementów
- testowanie, czy elementy już tam są
Prawie każdy język programowania powinien już mieć obsługę struktury danych, która może wykonywać obie te operacje w stałym ( ) czasie. Na przykład:O ( 1 )
set
w Pythonie
HashSet
w Javie
Na pierwszy rzut oka może się wydawać, że dodanie wszystkich stanów, które kiedykolwiek widziałeś, do takiego zestawu, będzie kosztowne pod względem pamięci, ale nie jest tak źle w porównaniu z pamięcią, której już potrzebujesz na swojej granicy; jeśli twój współczynnik rozgałęzienia wynosi , twoja granica wzrośnie o elementy na odwiedzany węzeł (usuń węzeł z granicy, aby go „odwiedzić”, dodaj nowych następców / dzieci), podczas gdy twój zestaw wzrośnie tylko o dodatkowy węzeł na odwiedzony węzeł.bb - 11b1
W pseudokodzie taki zestaw (nazwijmy go closed_set
, aby był spójny z pseudokodem na wikipedii, może być użyty w wyszukiwaniu szerokości w następujący sposób:
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
(niektóre odmiany tego pseudokodu mogą również działać i być mniej lub bardziej wydajne w zależności od sytuacji; na przykład możesz również wziąć closed_set
do wszystkich węzłów, których już dodałeś dzieci na granicy, a następnie całkowicie uniknąć generate_children()
połączenia jeśli current
jest już w closed_set
.)
To, co opisałem powyżej, byłoby standardowym sposobem radzenia sobie z tym problemem. Podejrzewam, że intuicyjnie innym „rozwiązaniem” może być zawsze losowa kolejność nowej listy stanów następczych przed dodaniem ich do granicy. W ten sposób nie unikniesz problemu od czasu do czasu dodawania stanów, które już wcześniej rozszerzyłeś na granicę, ale myślę, że powinno to znacznie zmniejszyć ryzyko utknięcia w nieskończonych cyklach.
Uwaga : nie znam żadnej formalnej analizy tego rozwiązania, która dowodzi, że zawsze unika się nieskończonych cykli. Jeśli spróbuję to „przelecieć” przez głowę, intuicyjnie, podejrzewam, że powinien to być rodzaj pracy i nie wymaga dodatkowej pamięci. Mogą być jednak przypadki krawędziowe, o których teraz nie myślę, więc może to po prostu nie działać, standardowe rozwiązanie opisane powyżej będzie bezpieczniejszym zakładem (kosztem większej ilości pamięci).