Алгоритм D* — различия между версиями
Kabanov (обсуждение | вклад) м (→Ссылки) |
Kabanov (обсуждение | вклад) |
||
Строка 11: | Строка 11: | ||
Аналогично множество <tex>Pred(s) \in V</tex> как множество вершин, входящих в вершину <tex>s</tex>. | Аналогично множество <tex>Pred(s) \in V</tex> как множество вершин, входящих в вершину <tex>s</tex>. | ||
− | Функция <tex>0 \ | + | Функция <tex>0 \lessgtr с(s, s') \lessgtr +\infty</tex> будет возвращать стоимость перехода из вершины <tex>s</tex> в вершину <tex>s'</tex>. При этом <tex>s' \in Succ(s)</tex>. |
Функция <tex>g(s)</tex> будет возвращать последнее известное (и самое минимальное) значение расстояния от вершины <tex>s_{start}</tex> до <tex>s</tex>. | Функция <tex>g(s)</tex> будет возвращать последнее известное (и самое минимальное) значение расстояния от вершины <tex>s_{start}</tex> до <tex>s</tex>. | ||
Строка 27: | Строка 27: | ||
Очевидно, что если все вершины насыщены, то мы можем найти расстояние от стартовой вершины до любой. | Очевидно, что если все вершины насыщены, то мы можем найти расстояние от стартовой вершины до любой. | ||
− | Функция <tex>key(s)</tex>, где <tex>s</tex> - вершина, возвращает вектор из 2-ух значений <tex>k_1(s)</tex>, <tex>k_2(s)</tex>. <tex>k_1(s) = min(g(s), rhs(s)) + h(s, s_goal)</tex>. <tex>k_2(s) = min(g(s), rhs(s))</tex> | + | Функция <tex>key(s)</tex>, где <tex>s</tex> - вершина, возвращает вектор из 2-ух значений <tex>k_1(s)</tex>, <tex>k_2(s)</tex>. |
+ | * <tex>k_1(s) = min(g(s), rhs(s)) + h(s, s_goal)</tex>. | ||
+ | * <tex>k_2(s) = min(g(s), rhs(s))</tex>. | ||
Если в конце поиска пути <tex>g(s_{goal}) = +\infty</tex>, то мы не смогли найти путь от <tex>s_{start}</tex> до <tex>s_{goal}</tex> на текущей итерации. Но после следующего изменения графа путь вполне может найтись. | Если в конце поиска пути <tex>g(s_{goal}) = +\infty</tex>, то мы не смогли найти путь от <tex>s_{start}</tex> до <tex>s_{goal}</tex> на текущей итерации. Но после следующего изменения графа путь вполне может найтись. | ||
Строка 65: | Строка 67: | ||
'''CalcKey'''(s): | '''CalcKey'''(s): | ||
{ | { | ||
− | return [<tex>\min(g(s); rhs(s)) + h(s; s_{goal})</tex>;<tex>\min(g(s); rhs(s))</tex>]; | + | return [<tex>\min(g(s); rhs(s)) + h(s; s_{goal})</tex>; <tex>\min(g(s); rhs(s))</tex>]; |
} | } | ||
Строка 92: | Строка 94: | ||
} | } | ||
− | Таким образом мы описали алгоритм LPA*. Он неоднократно определяет путь между вершинами <tex> | + | Таким образом мы описали алгоритм LPA*. Он неоднократно определяет путь между вершинами <tex>s_{start}</tex> и <tex>s_{goal}</tex>, используя при этом данные из предыдущих итераций. Очевидно, что в худшем случае (а именно когда все ребра вокруг текущей вершины изменили свой вес) алгоритм будет работать как последовательные вызовы алгоритма А* за <tex>O(n^2 \dot log(n))</tex>. Улучшим эту оценку с помощью алгоритма D* lite. |
'''Примечание''': на практике же такой подход тоже имеет место на плотных графах (или матрицах), так как в среднем дает оценку О(n*log(n)). | '''Примечание''': на практике же такой подход тоже имеет место на плотных графах (или матрицах), так как в среднем дает оценку О(n*log(n)). | ||
Строка 117: | Строка 119: | ||
U.Insert(u; CalcKey(u)); | U.Insert(u; CalcKey(u)); | ||
− | '''ComputeShortestPath'''() | + | '''ComputeShortestPath'''(): |
− | while (U.TopKey() < | + | while (U.TopKey() < CalcKey(<tex>s_{start}</tex>) OR <tex>rhs(s_{start}) \ne g(s_{start})</tex>) |
u = U.Pop(); | u = U.Pop(); | ||
if (g(u) > rhs(u)) | if (g(u) > rhs(u)) | ||
Строка 130: | Строка 132: | ||
'''Main'''(): | '''Main'''(): | ||
− | Initialize(); | + | '''Initialize'''(); |
− | ComputeShortestPath(); | + | '''ComputeShortestPath'''(); |
while (<tex>s_{start} \ne s_{goal}</tex>) | while (<tex>s_{start} \ne s_{goal}</tex>) | ||
// if (<tex>g(s_{start}) = \infty</tex>) тогда путь на данной итерации не найден. | // if (<tex>g(s_{start}) = \infty</tex>) тогда путь на данной итерации не найден. | ||
− | s_{start} = | + | <tex>s_{start}</tex> = такая вершина s', что <tex>min_{s' \in Succ(s_{start})}(c(s_{start}, s') + g(s'))</tex> |
− | + | Передвинулись вдоль найденного пути и изменили вершину <tex>s_{start}</tex>; | |
− | + | Ждем каких-либо изменений в графе или убеждаемся, что граф остается прежним. | |
− | if | + | if (если граф изменился) |
− | for | + | for всех ориентированных ребер <tex>(u; v)</tex> с измененными весами: |
− | + | Обновляем результат функции <tex>c(u; v)</tex>; | |
− | UpdateVertex(u); | + | '''UpdateVertex'''(u); |
for <tex>s \in U</tex> | for <tex>s \in U</tex> | ||
− | U.Update(<tex>s</tex>; CalcKey(<tex>s</tex>)); | + | U.Update(<tex>s</tex>; '''CalcKey'''(<tex>s</tex>)); |
ComputeShortestPath(); | ComputeShortestPath(); | ||
Версия 00:05, 3 января 2014
Алгоритм D* — алгоритм поиска кратчайшего пути во взвешенном ориентированном графе, где структура графа неизвестна заранее или постоянно подвергается изменению. Разработан Свеном Кёнигом и Максимом Лихачевым в 2002 году.
Содержание
Алгоритм LPA*
Постановка задачи
Дан взвешенный ориентированный граф
. Даны вершины и . Требуется после каждого изменения графа уметь вычислять функцию для каждой известной вершиныОписание
Обозначим множество
как множество вершин, исходящих из вершины .Аналогично множество
как множество вершин, входящих в вершину .Функция
будет возвращать стоимость перехода из вершины в вершину . При этом .Функция
будет возвращать последнее известное (и самое минимальное) значение расстояния от вершины до .Если
Иначе
Вершина
может быть 3-х видов:- насыщена, если
- переполнена, если
- ненасыщена, если
Очевидно, что если все вершины насыщены, то мы можем найти расстояние от стартовой вершины до любой.
Функция
, где - вершина, возвращает вектор из 2-ух значений , .- .
- .
Если в конце поиска пути
, то мы не смогли найти путь от до на текущей итерации. Но после следующего изменения графа путь вполне может найтись.Псевдокод
Основная функция, описывающая алгоритм
Main(): { Initialize(); while (true) { ComputeShortestPath(); В данный момент мы знаем кратчайший путь изв . Ждем каких-либо изменений графа. for всех ориентированных ребер с измененными весами: { Обновляем результат функции ; UpdateVertex( ); } } }
Теперь опишем составные элементы подробнее
Initialize(): { //Заведем приоритетную очередь, в которую будем помещать вершины. Сортировка будет производиться по функции . for U.Insert( ; CalcKey( )); }
Функция. Возвращаемые значения сортируются в лексографическом порядке, т.е. сначала , потом CalcKey(s): { return [ ; ]; }
UpdateVertex(): { if ( ) if ( ) U.Remove(u); if ( ) U.Insert( ; CalcKey( )); }
ComputeShortestPath(): { while (U.TopKey() < CalcKey() OR rhs( )) u = U.Pop(); if (g(u) > rhs(u)) g(u) = rhs(u); for UpdateVertex(s); else g(u) = ; for UpdateVertex(s); }
Таким образом мы описали алгоритм LPA*. Он неоднократно определяет путь между вершинами
и , используя при этом данные из предыдущих итераций. Очевидно, что в худшем случае (а именно когда все ребра вокруг текущей вершины изменили свой вес) алгоритм будет работать как последовательные вызовы алгоритма А* за . Улучшим эту оценку с помощью алгоритма D* lite.Примечание: на практике же такой подход тоже имеет место на плотных графах (или матрицах), так как в среднем дает оценку О(n*log(n)).
Алгоритм D*
Псевдокод (Первая версия)
CalcKey(s): return [; ];
Initialize(): U =; for U.Insert( ; CalcKey( ));
UpdateVertex(u): if () rhs(u) = min_{s' \in Succ(u)}(c(u,s')+g(s')); if ( ) U.Remove(u); if ( ) U.Insert(u; CalcKey(u));
ComputeShortestPath(): while (U.TopKey() < CalcKey() OR ) u = U.Pop(); if (g(u) > rhs(u)) g(u) = rhs(u); for UpdateVertex(s); else g(u) = ; for UpdateVertex(s);
Main(): Initialize(); ComputeShortestPath(); while () // if ( ) тогда путь на данной итерации не найден. = такая вершина s', что Передвинулись вдоль найденного пути и изменили вершину ; Ждем каких-либо изменений в графе или убеждаемся, что граф остается прежним. if (если граф изменился) for всех ориентированных ребер с измененными весами: Обновляем результат функции ; UpdateVertex(u); for U.Update( ; CalcKey( )); ComputeShortestPath();