Как сравнивается Dijkstra Algorithm и A-Star?

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

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

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

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

Ответ 1

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

Ответ 2

Дейкстра:

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

A * поиск:

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

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

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

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

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

Ответ 3

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

Ответ 4

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

Ответ 5

Дейкстра - частный случай для A *.

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

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

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

// A C / C++ program for Dijkstra 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 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)

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

Ответ 9

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

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

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

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

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

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

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

Ответ 10

Алгоритм Dijkstra определенно завершен и оптимален, что вы всегда найдете кратчайший путь. Однако он имеет тенденцию занимать больше времени, поскольку он используется в основном для обнаружения нескольких узлов цели.

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

Ответ 11

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

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

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