Puoi usare un set
(nel senso matematico della parola, cioè una collezione che non può contenere duplicati) per memorizzare gli stati che hai già visto. Le operazioni che devi essere in grado di eseguire su questo sono:
- inserimento di elementi
- verifica se gli elementi sono già presenti
Praticamente ogni linguaggio di programmazione dovrebbe già avere il supporto per una struttura di dati che può eseguire entrambe queste operazioni in tempo costante ( ). Per esempio:O ( 1 )
set
in Python
HashSet
in Java
A prima vista, può sembrare che aggiungere tutti gli stati che vedi in un set come questo sia costoso dal punto di vista della memoria, ma non è poi così male in confronto alla memoria di cui hai già bisogno per la tua frontiera; se il tuo fattore di ramificazione è , la tua frontiera crescerà di b - 1 elementi per nodo che visiti (rimuovi 1 nodo dalla frontiera per "visitarlo", aggiungi b nuovi successori / figli), mentre il tuo set crescerà solo di 1 extra nodo per nodo visitato.Bb - 11B1
In pseudocodice, un tale set (chiamiamolo closed_set
, per essere coerenti con lo pseudocodice su wikipedia potrebbe essere usato in una ricerca breadth-first come segue:
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
(alcune varianti di questo pseudocodice potrebbero anche funzionare, e potrebbero essere più o meno efficienti a seconda della situazione; ad esempio, potresti anche prendere closed_set
per contenere tutti i nodi di cui hai già aggiunto dei bambini alla frontiera, quindi evitare completamente la generate_children()
chiamata se current
è già nel closed_set
.)
Quello che ho descritto sopra sarebbe il modo standard di gestire questo problema. Intuitivamente, sospetto che una "soluzione" diversa potrebbe essere quella di randomizzare sempre l'ordine di un nuovo elenco di stati successori prima di aggiungerli alla frontiera. In questo modo, non eviti il problema di aggiungere occasionalmente stati che hai già precedentemente espanso alla frontiera, ma penso che dovrebbe ridurre significativamente il rischio di rimanere bloccati in cicli infiniti.
Fai attenzione : non conosco alcuna analisi formale di questa soluzione che dimostri che evita sempre cicli infiniti. Se provo a "farcela" in modo intuitivo, sospetto che dovrebbe funzionare, e non richiede memoria aggiuntiva. Potrebbero esserci casi limite a cui non sto pensando in questo momento, quindi semplicemente potrebbe non funzionare, la soluzione standard sopra descritta sarà una scommessa più sicura (al costo di più memoria).