Dijkstra의 알고리즘과 A- 스타는 어떻게 비교됩니까?


154

나는 마리오 AI 경쟁 의 사람들이 무엇을하고 있었는지보고 있었고, 그들 중 일부는 A * (A-Star) Pathing Algorithm을 사용하여 아주 깔끔한 마리오 봇을 만들었습니다.

대체 텍스트
( 마리오 A * 봇 작동 비디오 )

제 질문은 A-Star가 Dijkstra와 어떻게 비교됩니까? 그것들을 살펴보면 비슷해 보입니다.

왜 누군가가 다른 것을 사용합니까? 특히 게임에서의 경로와 관련하여?



@SLaks A *는 dijkstra보다 더 많은 메모리를 사용합니까? dijkstra가 모든 노드를 시도하는 동안 유망한 노드 만 경로 지정하면 어떻게 되나요?
Poutrathor

답변:


177

Dijkstra는 A *의 특별한 경우입니다 (휴리스틱이 0 인 경우).


1
dijkstra에서는 소스와의 거리 만 고려합니까? 그리고 최소 정점이 고려됩니까?
Kraken

4
나는 A *가 휴리스틱을 사용하는 Dijkstra의 특별한 경우라고 생각했습니다. Dijkstra가 처음으로 afaik에 있었기 때문에.
Madmenyo

46
@ MennoGouw : 예 Dijkstra의 알고리즘이 먼저 개발되었습니다; 그러나 더 일반적인 알고리즘 A *의 특별한 경우입니다. 특별한 경우가 먼저 발견 된 다음에 일반화되는 것이 전혀 이상하지는 않습니다 (사실, 아마도 표준).
Pieter Geerkens

1
휴리스틱을 아는 사람에게는 훌륭한 답변;)
lindhe

1
A *와 휴리스틱 사용에 대해서는 Norvig와 Russel의 AI 책
BoltzmannBrain

113

다이크 스트라 :

여기에는 소스에서 각 노드까지의 실제 비용 값인 하나의 비용 함수가 f(x)=g(x)있습니다.
실제 비용 만 고려하여 소스에서 다른 모든 노드로의 최단 경로를 찾습니다.

검색:

두 가지 비용 함수가 있습니다.

  1. g(x): Dijkstra와 동일 노드에 도달하는 실제 비용 x.
  2. h(x): 노드 x에서 목표 노드 까지의 대략적인 비용 . 휴리스틱 함수입니다. 이 휴리스틱 함수는 비용을 과대 평가해서는 안됩니다. 즉, 노드에서 목표 노드에 도달하는 실제 비용 x은보다 크거나 같아야 h(x)합니다. 허용되는 휴리스틱이라고합니다.

각 노드의 총 비용은 f(x)=g(x)+h(x)

A * 검색은 유망한 것으로 보이는 경우에만 노드를 확장합니다. 다른 모든 노드에 도달하지 않고 현재 노드에서 목표 노드에 도달하는 데에만 초점을 맞 춥니 다. 휴리스틱 기능이 허용되는 경우 최적입니다.

따라서 휴리스틱 함수가 미래 비용을 근사하기에 좋은 경우 Dijkstra보다 훨씬 적은 수의 노드를 탐색해야합니다.


20

Dijkstra는 휴리스틱이 없으며 각 단계에서 가장 작은 비용으로 가장자리를 선택하기 때문에 이전 포스터의 내용과 함께 더 많은 그래프를 "덮는"경향이 있습니다. Dijkstra는 A *보다 유용 할 수 있습니다. 좋은 예는 여러 후보 대상 노드가 있지만 어느 것이 가장 가까운 지 모르는 경우입니다 (A *의 경우 여러 번 실행해야합니다 (각 후보 노드마다 한 번씩)).


17
몇 가지 잠재적 목표 노드가있는 경우 목표 테스트 기능을 변경하여 목표 노드를 모두 포함 할 수 있습니다. 이런 식으로 A *는 한 번만 실행하면됩니다.
Brad Larsen

9

Dijkstra의 알고리즘은 경로 찾기에 절대 사용되지 않습니다. 괜찮은 휴리스틱 (일반적으로 게임, 특히 2D 세계에서 쉬움)을 생각해 낼 수 있다면 A *를 사용하는 것은 쉬운 일이 아닙니다. 검색 공간에 따라 반복 심화 A *가 적은 메모리를 사용하기 때문에 선호되는 경우가 있습니다.


5
Dijkstra가 왜 길 찾기에 사용되지 않습니까? 정교하게 할 수 있습니까?
KingNestor

2
까다로운 휴리스틱을 생각 해낼 수 있더라도 Dijkstra보다 낫습니다. 때로는 허용되지 않는 경우에도 마찬가지입니다. 도메인에 따라 다릅니다. Dijkstra는 메모리 부족 상황에서도 작동하지 않지만 IDA *는 작동합니다.
얽히고 설킨 개구리


7

Dijkstra는 A *의 특별한 경우입니다.

Dijkstra는 시작 노드에서 다른 모든 노드까지의 최소 비용을 찾습니다. A *는 시작 노드에서 목표 노드까지의 최소 비용을 찾습니다.

Dijkstra의 알고리즘은 경로 찾기에 사용되지 않습니다. A *를 사용하면 괜찮은 휴리스틱을 얻을 수 있습니다. 검색 공간에 따라 반복적 인 A *가 더 적은 메모리를 사용하므로 바람직합니다.

Dijkstra의 알고리즘 코드는 다음과 같습니다.

// 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)

이미 닫힌 세트에있는 이웃을 건너 뛰면 차선책이됩니다. 그래프 (YouTube 비디오의 경우 언어를 무시하십시오) 에서 시도하면 잘못된 답변을 제공합니다.
itsjwala

5

Dijkstra는 시작 노드에서 다른 모든 노드까지의 최소 비용을 찾습니다. A *는 시작 노드에서 목표 노드까지의 최소 비용을 찾습니다.

따라서 Dijkstra는 한 노드에서 다른 노드까지의 최소 거리 만 있으면 효율성이 떨어질 것입니다.


2
사실이 아닙니다. 표준 Dijkstra는 두 점 사이의 최단 경로를 제공하는 데 사용됩니다.
Emil

3
Dijkstra의 결과는 s에서 다른 모든 정점으로 결과를 제공합니다. 따라서 느리게 작동합니다.
Ivan Voroshilin

나는 두 번째 @Emil 의견. 우선 순위 대기열에서 대상 노드를 제거 할 때 중지하고 소스에서 대상까지의 경로가 가장 짧습니다. 이것이 실제로 원래 알고리즘이었습니다.
seteropere

보다 정확하게 : 목표가 지정되면 Dijkstra는 지정된 목표까지의 경로보다 짧은 경로에있는 모든 노드에 대한 최단 경로를 찾습니다. A *에서 휴리스틱의 목적은 이러한 경로 중 일부를 정리하는 것입니다. 휴리스틱의 효과는 정리할 수를 결정합니다.
Waylon Flinn 2012

@seteropere, 그러나 목적지 노드가 마지막으로 검색된 노드라면? 목적지 노드가 검색되었는지 확인하는 데 도움이 목록의 마지막 노드가 아닌 무엇가 있기 때문에, 확실히 덜 효율적인 *의 휴리스틱 및 우선 순위 노드를 선택하고
Knight0fDragon

5

A *를 Dijkstra의 안내 버전으로 고려할 수 있습니다. 즉, 모든 노드를 탐색하는 대신 휴리스틱을 사용하여 방향을 선택합니다.

더 구체적으로 말하자면, 우선 순위 대기열로 알고리즘을 구현하는 경우 방문하는 노드의 우선 순위는 비용 (이전 노드 비용 + 여기에 도달하는 비용)과 여기에서 발견되는 추론의 함수입니다. 목표에. Dijkstra에서 우선 순위는 실제 노드 비용에 의해서만 영향을받습니다. 두 경우 모두 정지 기준이 목표에 도달하고 있습니다.


2

Dijkstra의 알고리즘은 가장 짧은 경로를 확실히 찾습니다. 반면에 A *는 휴리스틱에 따라 다릅니다. 이러한 이유로 A *는 Dijkstra의 알고리즘보다 빠르며 휴리스틱이 양호하면 좋은 결과를 얻을 수 있습니다.


4
A *는 Dijkstra와 동일한 결과를 제공하지만 우수한 휴리스틱을 사용할 때 더 빠릅니다. A * 알고리즘은 현재 노드와 최종 노드 사이의 추정 거리가 실제 거리보다 낮아야하는 등 올바르게 작동하기위한 일부 조건을 부과합니다.
Alexandru

4
휴리스틱이 허용되는 경우 A *는 최단 경로를 보장합니다 (항상 과소 평가)
Robert

1

Astar 의 psuedocode 를 보면 :

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는 휴리스틱
으로 인해 노드를 한 번만 보는 것으로 충분하기 때문에 노드를 두 번 이상 평가하지 않을 것
입니다.

Dijkstra의 알고리즘 인 OTOH
는 노드가 다시 팝업 되는 경우 자체 수정을 부끄러워하지 않습니다 .

어느 해야 보다 신속하고 적절한 경로 발견을위한 아스타을합니다.


7
이것은 사실이 아닙니다. A *는 노드를 두 번 이상 볼 수 있습니다. 사실, Dijkstra는 A *의 특별한 경우입니다.
Emil

2
설명을 위해 이것을 확인하십시오 : stackoverflow.com/questions/21441662/…
spiralmoon

모든 검색 알고리즘에는 "프론티어"와 "방문 집합"이 있습니다. 알고리즘은 방문 세트에있는 노드에 대한 경로를 수정하지 않습니다. 설계에 따라 노드가 우선 순위에서 방문 세트로 노드를 이동합니다. 알려진 거리는 노드가 경계에있는 동안에 만 업데이트 할 수 있습니다. Dijkstra는 최우선 검색의 한 형태이며 "방문 된"세트에 배치 된 노드는 다시 방문하지 않습니다. A *는이 특성을 공유하며 보조 추정기를 사용하여 프론티어에서 우선 순위를 지정할 노드를 선택합니다. en.wikipedia.org/wiki/Dijkstra%27s_algorithm
pygosceles 2013

0

A *에서 각 노드에 대해 나가는 연결을 확인합니다.
새 노드마다이 노드에 대한 연결 가중치와 이전 노드에 도달해야하는 비용에 따라 지금까지 최저 비용 (csf)을 계산합니다.
또한 새 노드에서 대상 노드까지의 비용을 추정하고이를 csf에 추가합니다. 이제 예상 총 비용 등이 있습니다. (등 = CSF + 추정 대상까지의 거리) 다음은 당신이 등 가장 낮은과 하나가 새로운 노드 선택
중 하나까지 이전과 동일한 작업을 수행 새 노드가 대상이됩니다.

Dijkstra는 거의 동일하게 작동합니다. 타겟까지의 추정 거리가 항상 0 인 것을 제외하고는 타겟이 새로운 노드 중 하나 일뿐만 아니라 가장 낮은 csf를 가진 노드 일 때 알고리즘이 먼저 중지됩니다 .

A *는 일반적으로 dijstra보다 빠르지 만 항상 그런 것은 아닙니다. 비디오 게임에서는 종종 "게임에 충분히 근접한"접근 방식을 사용합니다. 따라서 A *에서 "충분히 근접한"최적 경로로 충분합니다.


-1

Dijkstra의 알고리즘은 완벽하고 완벽하며 항상 가장 짧은 경로를 찾을 수 있습니다. 그러나 여러 목표 노드를 감지하는 데 주로 사용되므로 시간이 오래 걸립니다.

A* search반면 휴리스틱 값은 중요합니다.이 값은 맨해튼 목표 거리와 같이 가까운 목표에 도달하도록 정의 할 수 있습니다. 휴리스틱 요소에 따라 최적이거나 완전 할 수 있습니다. 단일 목표 노드가 있으면 확실히 빠릅니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.