#search #graph #path #breadth-first-search #a-star
Вопрос:
Я недавно изучаю поиск по графу и поиск по дереву, и я вижу, что во многих примерах упоминается что-то вроде «путь, возвращаемый поиском по графику xxx,…» Однако поиск по графу-это метод обхода, как он может возвращать путь?
Мы знаем, что при поиске по дереву каждый узел соответствует определенному пути, и, посетив узел, мы узнаем соответствующий путь. Я достаточно хорошо знаком с поиском по деревьям, но при поиске по графам цель состоит в том, чтобы посетить пункт назначения, а не найти путь к месту назначения. Тогда как мы можем определить путь, возвращаемый поиском по графику?
Например, ниже приведен график.
Graph
B
/
/
Start Destination
/
/
C
Когда мы делаем BFS на старте, последовательность посещений- Start-B-C-Destination
или Start-C-B-Destination
. Тогда каким должен быть обратный путь? Если мы используем очередь, мы можем сказать, что мы ставим в очередь Destination
при посещении B
(или C
), поэтому возвращаемый путь Start-B-Destination
(или Start-C-Destination
), тогда как насчет следующего графика?
Graph
B
/
/
Start-----D-----Destination
/
/
C
Очевидно, D
что при посещении ставится Start
в очередь , поэтому единственным возможным путем должен быть Start-D-Destination
?
В поиске* возникает больше проблем. Если узел посещается не по кратчайшему пути (из-за плохой эвристической функции), то каким должен быть конечный возвращаемый путь? Например, на приведенном ниже графике последовательность посещений такова Start-B-D-C-Destination
, то каким должен быть возвращаемый путь? Start-B-D-Destination
или Start-C-D-Destination
? Мы посетили D
, когда B
находимся на окраине, однако, когда мы рассчитываем стоимость от Start
до D
, мы рассчитываем Start-C-D
, и стоимость должна быть 2, а не 3.
Graph
B
/
1 2
/
Start D--5--Destination
/
1 1
/
C
h(B) = 2, h(C) = 4, h(D) = 1
Я думаю, что все эти проблемы вызваны намерением поиска по графику не найти путь, и поиск по графику приведет к неоднозначности при выборе того, какой узел должен быть включен в окончательный путь.
Спасибо за ваше терпение, и я буду очень признателен, если кто-нибудь сможет дать мне ответ.
Комментарии:
1. Предложение: прочитайте об алгоритме Dijsktra en.wikipedia.org/wiki/Dijkstra’s_algorithm
2. Алгоритм Дейкстры, как алгоритм поиска по графу, может возвращать путь, потому что мы знаем, как получается кратчайший путь к определенному узлу. Предыдущий узел A в пути-это узел, который обновляет расстояние A. В таких случаях, как BFS, такой связи нет.
Ответ №1:
Я буду использовать ваш пример:
B
/
1 2
/
Start D--5--Destination
/
1 1
/
C
Обратите внимание, что чистый поиск по ширине не обращает внимания на вес ребер (или стоимость). В этом случае первым путем, который приведет его к месту назначения, может быть Start->B->D->Destination
.
Он помечает каждый узел, который он посещает, логическим флагом, чтобы указать, что узел был посещен, чтобы он не преследовал Start->B->Start->C->Start->...
, чтобы запомнить успешный путь, мы должны где-то хранить немного больше информации. Один из простых подходов состоит в том, чтобы пометить каждый узел не только visited
флагом, но и ссылкой на узел , с которого он был посещен. Поэтому, если порядок посещения был Start, B, C, D, Destination
, график будет выглядеть следующим образом:
B(Start)
/
1 2
/
Start D(B)--5--Destination(D)
/
1 1
/
C(Start)
Тогда мы сможем вернуться назад. Как мы до этого добрались Destination
? От D
. Как мы до этого добрались D
? От B
. Как мы до этого добрались B
? От Start
.
Поиск по ширине сначала следует за первым ребром в очереди и находит кратчайший путь (в смысле наименьшего числа ребер). Если нам нужен путь с наименьшим весом (самый дешевый), мы изменяем поиск, чтобы отслеживать стоимость доступа к этому узлу, и следуем по краю, который достигает нового узла наиболее дешево. (Это одна из версий алгоритма Дейкстры.) Тогда в этом случае порядок посещения будет таким же, но мы будем посещать D
с C
, а не с B
, и получим путь Start->C->D->Destination
.
С помощью A*, используя h(B) = 2, h(C) = 4, h(D) = 1, порядок посещения Start, B, D, C, D, Destination
и путь Start->C->D->Destination
.
Комментарии:
1. Спасибо за ваше объяснение! Я думаю, что понимаю большую часть содержания. Итак, согласно вашему ответу, на моем втором графике, если мы используем BFS, единственный возможный путь
Start-D-Destination
-это, а если мы используем DFS, все три пути возможны, верно?
Ответ №2:
Для BFS есть два варианта:
- Когда вы ставите узел в очередь, отметьте, от какого соседа вы исходите. Затем в конце каждый узел на лучшем пути будет иметь ссылку на «предыдущий» узел на пути, поэтому вы можете вернуться непосредственно от пункта назначения к началу, чтобы найти путь.
- Когда вы ставите узел в очередь, отметьте лучший путь к этому узлу, который является просто лучшим путем к его соседу, плюс край, который вы выбрали.
Вариант 1-это то, что обычно делается, потому что это более эффективно.
Для Дейкстры (BFS для взвешенных графов), то же самое верно, за исключением того, что когда тебя поставит узел в очереди и отмечают, что сосед пришел, ты не должен нашли лучший путь к этому узлу. Если в дальнейшем вы столкнулись с такой же узел с другого соседа, вы должны сравнить суммарные расстояния обоих вариантов, и выбрать более короткий-как «назад» узел.
Это сделано в строках 18-20 псевдокода в Википедии
18 if alt < dist[v]:
19 dist[v] ← alt
20 prev[v] ← u
Как только вы развернете узел (удалите его из очереди приоритетов), вы гарантированно найдете лучший путь к узлу.
Для A* ситуация такая же, как у Дейкстры, если эвристика непротиворечива. Однако, если эвристика допустима только в этом случае, то вы не гарантируете, что нашли наилучший путь к узлу при его первом развертывании. В этом случае вам может потребоваться поставить в очередь и развернуть один и тот же узел несколько раз.
По этой причине на самом деле не очень часто используется* с несогласованной эвристикой.
Комментарии:
1. Спасибо! Я думаю, что я неправильно понял* поиск, потому что я не понял, что узел может быть посещен несколько раз в* поиске.
2. Означает ли это, что* поиск может, наконец, вернуть кратчайший путь, даже если эвристическая функция не согласована?
3. @цитрат: Если эвристика непротиворечива, A* гарантированно вернет кратчайший путь, и всякий раз, когда узел расширяется, он гарантированно будет кратчайшим путем к этому узлу. Если эвристика допустима, но не согласована, то A* гарантированно вернет кратчайший путь, но узлы, возможно, потребуется расширить несколько раз. Если эвристика неприемлема, она может не возвращать кратчайший путь (на самом деле это используется в качестве преимущества некоторых других алгоритмов, но это другое обсуждение).