Как сравниваются алгоритм Дейкстры и A-Star? - PullRequest
145 голосов
/ 26 августа 2009

Я смотрел на то, что делали ребята в Mario AI Competition , и некоторые из них создали несколько довольно аккуратных ботов Mario, используя алгоритм A * (A-Star) Pathing.

alt text
( Видео Марио A * Bot In Action )

Мой вопрос: как A-Star сравнивается с Dijkstra? Глядя на них, они кажутся похожими.

Зачем кому-то использовать один поверх другого? Особенно в контексте путей в играх?

Ответы [ 11 ]

168 голосов
/ 26 августа 2009

Дейкстра является частным случаем для A * (когда эвристика равна нулю).

107 голосов
/ 29 апреля 2013

Дейкстр:

Имеет одну функцию стоимости, которая является реальной стоимостью от источника до каждого узла: f(x)=g(x).
Он находит кратчайший путь от источника к каждому другому узлу, учитывая только реальную стоимость.

A * поиск:

Имеет две функции стоимости.

  1. g(x): то же, что Дейкстра. Реальная стоимость достижения узла x.
  2. h(x): приблизительная стоимость от узла x до узла цели. Это эвристическая функция. Эта эвристическая функция никогда не должна переоценивать стоимость. Это означает, что реальная стоимость достижения узла цели из узла x должна быть больше или равна h(x). Это называется допустимым эвристическим.

Общая стоимость каждого узла рассчитывается по f(x)=g(x)+h(x)

Поиск * расширяет узел, только если он кажется многообещающим. Он фокусируется только на достижении целевого узла с текущего узла, а не на всех остальных узлах. Оптимально, если допустима эвристическая функция.

Так что, если ваша эвристическая функция хороша для приближения будущей стоимости, вам нужно будет исследовать намного меньше узлов, чем Дейкстра.

20 голосов
/ 26 августа 2009

То, что сказал предыдущий автор, плюс к тому, что у Дейкстры нет эвристики, и на каждом шаге она выбирает ребра с наименьшими затратами, что имеет тенденцию «покрывать» больше вашего графика. Из-за этого Dijkstra может быть более полезным, чем A *. Хорошим примером является случай, когда у вас есть несколько целевых узлов-кандидатов, но вы не знаете, какой из них ближе всего (в случае A * вам придется запускать его несколько раз: один раз для каждого узла-кандидата).

8 голосов
/ 26 августа 2009

Алгоритм Дейкстры никогда не будет использоваться для поиска пути. Использование A * не представляет никакой сложности, если вы можете придумать приличную эвристику (обычно легко для игр, особенно в 2D-мирах). В зависимости от пространства поиска, итеративное углубление A * иногда предпочтительнее, поскольку оно использует меньше памяти.

6 голосов
/ 14 марта 2017

Дейкстра - особый случай для А *.

Дейкстра находит минимальные затраты от начального узла до всех остальных. A * находит минимальную стоимость от начального узла до целевого узла.

Алгоритм Дейкстры никогда не будет использоваться для поиска пути. Используя A *, можно придумать приличную эвристику. В зависимости от пространства поиска предпочтительным является итеративный A *, поскольку он использует меньше памяти.

Код алгоритма Дейкстры:

// A C / C++ program for Dijkstra's single source shortest path algorithm.
// The program is for adjacency matrix representation of the graph

#include <stdio.h>
#include <limits.h>

// Number of vertices in the graph
#define V 9

// A utility function to find the vertex with minimum distance value, from
// the set of vertices not yet included in shortest path tree
int minDistance(int dist[], bool sptSet[])
{
 // Initialize min value
 int min = INT_MAX, min_index;

  for (int v = 0; v < V; v++)
   if (sptSet[v] == false && dist[v] <= min)
     min = dist[v], min_index = v;

   return min_index;
}

 int printSolution(int dist[], int n)
 {
  printf("Vertex   Distance from Source\n");
  for (int i = 0; i < V; i++)
     printf("%d \t\t %d\n", i, dist[i]);
  }

void dijkstra(int graph[V][V], int src)
{
 int dist[V];     // The output array.  dist[i] will hold the shortest
                  // distance from src to i

 bool sptSet[V]; // sptSet[i] will true if vertex i is included in shortest
                 // path tree or shortest distance from src to i is finalized

 // Initialize all distances as INFINITE and stpSet[] as false
 for (int i = 0; i < V; i++)
    dist[i] = INT_MAX, sptSet[i] = false;

 // Distance of source vertex from itself is always 0
 dist[src] = 0;

 // Find shortest path for all vertices
 for (int count = 0; count < V-1; count++)
 {
   // Pick the minimum distance vertex from the set of vertices not
   // yet processed. u is always equal to src in first iteration.
   int u = minDistance(dist, sptSet);

   // Mark the picked vertex as processed
   sptSet[u] = true;

   // Update dist value of the adjacent vertices of the picked vertex.
   for (int v = 0; v < V; v++)

     // Update dist[v] only if is not in sptSet, there is an edge from 
     // u to v, and total weight of path from src to  v through u is 
     // smaller than current value of dist[v]
     if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX 
                                   && dist[u]+graph[u][v] < dist[v])
        dist[v] = dist[u] + graph[u][v];
 }

 // print the constructed distance array
 printSolution(dist, V);
 }

// driver program to test above function
int main()
 {
 /* Let us create the example graph discussed above */
 int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0},
                  {4, 0, 8, 0, 0, 0, 0, 11, 0},
                  {0, 8, 0, 7, 0, 4, 0, 0, 2},
                  {0, 0, 7, 0, 9, 14, 0, 0, 0},
                  {0, 0, 0, 9, 0, 10, 0, 0, 0},
                  {0, 0, 4, 14, 10, 0, 2, 0, 0},
                  {0, 0, 0, 0, 0, 2, 0, 1, 6},
                  {8, 11, 0, 0, 0, 0, 1, 0, 7},
                  {0, 0, 2, 0, 0, 0, 6, 7, 0}
                 };

dijkstra(graph, 0);

return 0;
}

Код для алгоритма A *:

class Node:
def __init__(self,value,point):
    self.value = value
    self.point = point
    self.parent = None
    self.H = 0
    self.G = 0
def move_cost(self,other):
    return 0 if self.value == '.' else 1

def children(point,grid):
x,y = point.point
links = [grid[d[0]][d[1]] for d in [(x-1, y),(x,y - 1),(x,y + 1),(x+1,y)]]
return [link for link in links if link.value != '%']
def manhattan(point,point2):
return abs(point.point[0] - point2.point[0]) + abs(point.point[1]-point2.point[0])
def aStar(start, goal, grid):
#The open and closed sets
openset = set()
closedset = set()
#Current point is the starting point
current = start
#Add the starting point to the open set
openset.add(current)
#While the open set is not empty
while openset:
    #Find the item in the open set with the lowest G + H score
    current = min(openset, key=lambda o:o.G + o.H)
    #If it is the item we want, retrace the path and return it
    if current == goal:
        path = []
        while current.parent:
            path.append(current)
            current = current.parent
        path.append(current)
        return path[::-1]
    #Remove the item from the open set
    openset.remove(current)
    #Add it to the closed set
    closedset.add(current)
    #Loop through the node's children/siblings
    for node in children(current,grid):
        #If it is already in the closed set, skip it
        if node in closedset:
            continue
        #Otherwise if it is already in the open set
        if node in openset:
            #Check if we beat the G score 
            new_g = current.G + current.move_cost(node)
            if node.G > new_g:
                #If so, update the node to have a new parent
                node.G = new_g
                node.parent = current
        else:
            #If it isn't in the open set, calculate the G and H score for the node
            node.G = current.G + current.move_cost(node)
            node.H = manhattan(node, goal)
            #Set the parent to our current item
            node.parent = current
            #Add it to the set
            openset.add(node)
    #Throw an exception if there is no path
    raise ValueError('No Path Found')
def next_move(pacman,food,grid):
#Convert all the points to instances of Node
for x in xrange(len(grid)):
    for y in xrange(len(grid[x])):
        grid[x][y] = Node(grid[x][y],(x,y))
#Get the path
path = aStar(grid[pacman[0]][pacman[1]],grid[food[0]][food[1]],grid)
#Output the path
print len(path) - 1
for node in path:
    x, y = node.point
    print x, y
pacman_x, pacman_y = [ int(i) for i in raw_input().strip().split() ]
food_x, food_y = [ int(i) for i in raw_input().strip().split() ]
x,y = [ int(i) for i in raw_input().strip().split() ]

grid = []
for i in xrange(0, x):
grid.append(list(raw_input().strip()))

next_move((pacman_x, pacman_y),(food_x, food_y), grid)
4 голосов
/ 28 мая 2015

Вы можете считать A * управляемой версией Dijkstra. Это означает, что вместо изучения всех узлов, вы будете использовать эвристику, чтобы выбрать направление.

Проще говоря, если вы реализуете алгоритмы с приоритетной очередью, то приоритет посещаемого узла будет зависеть от стоимости (стоимость предыдущих узлов + стоимость, чтобы добраться сюда) и эвристики. оценить отсюда до цели. В то время как в Dijkstra, приоритет зависит только от фактической стоимости для узлов. В любом случае критерий остановки достигает цели.

4 голосов
/ 23 мая 2010

Дейкстра находит минимальные затраты от начального узла до всех остальных. * Находит минимальную стоимость от начального узла до узла цели.

Поэтому может показаться, что Дейкстра будет менее эффективен, когда все, что вам нужно, это минимальное расстояние от одного узла до другого.

2 голосов
/ 05 декабря 2010

Если вы посмотрите на psuedocode для Astar:

foreach y in neighbor_nodes(x)
             if y in closedset
                 continue

Принимая во внимание то же самое для Дейкстры :

for each neighbor v of u:         
             alt := dist[u] + dist_between(u, v) ;

Итак, смысл в том, что Астар не будет оценивать узел более одного раза,
поскольку он считает, что достаточно один раз посмотреть на узел, из-за
к его эвристике.

OTOH, алгоритм Дейкстры не стесняется исправлять себя, в случае
узел снова появляется.

Что должно сделать Астар быстрее и более подходящим для поиска пути.

2 голосов
/ 20 сентября 2009

Алгоритм Дейкстры определенно находит кратчайший путь. С другой стороны, A * зависит от эвристики. По этой причине A * быстрее алгоритма Дейкстры и даст хорошие результаты, если у вас хорошая эвристика.

0 голосов
/ 11 июня 2013

В A * для каждого узла вы проверяете исходящие соединения на их.
Для каждого нового узла вы рассчитываете самую низкую стоимость (csf), в зависимости от веса подключений к этому узлу и затрат, которые вам пришлось достичь на предыдущем узле.
Кроме того, вы оцениваете стоимость от нового узла до целевого узла и добавляете ее к csf. Теперь у вас есть приблизительная общая стоимость (и т. Д.). (и т. д. = csf + приблизительное расстояние до цели) Далее вы выбираете из новых узлов один с самым низким и т. Д.
Делайте то же, что и раньше, пока один из новых узлов не станет целью.

Дейкстра работает почти так же. За исключением того, что предполагаемое расстояние до цели всегда равно 0, и алгоритм сначала останавливается, когда целью является не только один из новых узлов , но и узел с самым низким значением csf.

A * обычно быстрее, чем dijstra, хотя это не всегда так. В видеоиграх вы часто предпочитаете подход «достаточно близко для игры». Поэтому обычно достаточно «близкого» оптимального пути от A *.

...