Я думаю, это связано с тем, как реализован двунаправленный поиск.
Псевдокод для BFS выглядит примерно так:
until frontier.empty?
node <- frontier.pop()
add node to explored
for each child not in expored or frontier:
if child is goal then
return path
add child to frontier
Представьте, что вы реализуете двунаправленный поиск следующим образом:
until frontierForward.emtpy? or frontierBackward.empty?
node <- frontierForward.pop()
add node to exploredForward
for each child not in exporedForward or frontierForward:
if child in frontierBackward then
return pathForward + pathBackward
add child to frontierForward
Do something similar but now searching backwards
В основном, чередующиеся шаги «вперед» BFS и «назад» BFS. Теперь представьте график, подобный следующему:
B-C-D
/ \
A E
\ /
F - G
Первый прогон BFS вперед и назад дал бы нам такое состояние:
1) expandedForward = A ; frontierForward = B, F
2) expandedBackward = E ; frontierBackward = D, G
Теперь алгоритм выбирает следующий узел для расширения от прямой границы, и он выбирает B.
3) expandedForward = A, B ; frontierForward = F, C
Теперь мы запускаем обратную BFS и расширяем узел D. Дочерний элемент D, C, находится на прямой границе, поэтому мы возвращаем путь A - B - C - D - E.
Я думаю, что это то, на что ссылаются Рассел и Норвиг. Если реализация не учитывает этот сценарий, она может дать вам решение, которое не является оптимальным.
Он должен завершить расширение всех узлов на границе, имеющих одинаковую «глубину», прежде чем решить, что нашел оптимальное решение. Или может чередовать прямой и обратный поиск BFS по уровням, а не по узлам (развернуть вперед все узлы на уровне 0, развернуть назад все узлы на уровне 0, развернуть вперед все узлы на уровне 1 и т. Д.)