如果正确实施,A *路径查找算法是否可以保证找到最短路径100%或时间?
int Graph::FindPath(Node *start, Node *finish, list< vec2f > &path)
{
list<NodeRecord*> open;
list<NodeRecord*> closed;
list<NodeRecord*>::iterator openIt;
list<NodeRecord*>::iterator closedIt;
// add the starting node to the open list
open.push_back( new NodeRecord(start, NULL, 0.0f, 0.0f + start->pos.DistanceSq(finish->pos) ) );
// NodeRecord(Node *node, Node *from, float cost, float totalCost)
while(!open.empty())
{
// find the node record with the lowest cost
NodeRecord *currentRecord = open.front();
openIt = ++open.begin();
while(openIt != open.end())
{
if((*openIt)->total < currentRecord->total)
currentRecord = (*openIt);
openIt++;
}
// get a pointer to the current node
Node *currentNode = currentRecord->node;
// if the current node is the finish point
if(currentNode == finish)
{
// add the finish node
path.push_front(currentNode->pos);
// add all the from nodes
Node *from = currentRecord->from;
while(!closed.empty())
{
// if this node record is where the path came from,
if(closed.back()->node == from) //&& closed.back()->from != NULL
{
// add it to the path
path.push_front( from->pos );
// get the next 'from' node
from = closed.back()->from;
}
// delete the node record
delete closed.back();
closed.pop_back();
}
while(! open.empty() )
{
delete open.back();
open.pop_back();
}
// a path was found
return 0;
}
// cycle through all neighbours of the current node
bool isClosed, isOpen;
for(int i = 0; i < (int)currentNode->neighbours.size(); i++)
{
// check if neigbour is on the closed list
isClosed = false;
closedIt = closed.begin();
while(closedIt != closed.end())
{
if(currentNode->neighbours[i] == (*closedIt)->node)
{
isClosed = true;
break;
}
closedIt++;
}
// skip if already on the closed list
if(isClosed == true)
continue;
float cost = currentRecord->cost + currentNode->distance[i];
float totalCost = cost + currentNode->neighbours[i]->pos.DistanceSq(finish->pos);
// check if this neighbour is already on the open list
isOpen = false;
openIt = open.begin();
while(openIt != open.end())
{
if(currentNode->neighbours[i] == (*openIt)->node)
{
// node was found on the open list
if(totalCost < (*openIt)->total)
{
// node on open list was updated
(*openIt)->cost = cost;
(*openIt)->total = totalCost;
(*openIt)->from = currentNode;
}
isOpen = true;
break;
}
openIt++;
}
// skip if already on the open list
if(isOpen == true)
continue;
// add to the open list
open.push_back( new NodeRecord(currentNode->neighbours[i], currentNode, cost, totalCost) );
}
// move the current node to the closed list after it has been evaluated
closed.push_back( currentRecord );
open.remove( currentRecord );
}
// free any nodes left on the closed list
while(! closed.empty() )
{
delete closed.back();
closed.pop_back();
}
// no path was found
return -1;
}
答案 0 :(得分:14)
Yes(但我没有深入研究你的实施)。
大多数人都错过的是启发式算法必须低估最终解决方案的遍历成本(这称为“admissible”)。启发式单调处理解决方案也很好(但并非绝对必要)(这称为“consistent”)
无论如何,在我看一下您的代码时,您可能应该使用std::set
作为已关闭的列表,并使用std::deque
作为您的开放代码,以便您在这两个列表中的搜索和插入不是O( N)。你也不应该new NodeRecords
,因为它给你一个没有任何好处的间接级别(如果抛出异常,你的算法会泄漏内存)。
答案 1 :(得分:5)
根据Wikipedia,A *使用启发式算法来更快地找到最短路径,但实际上它是对Dijkstra最短路径算法的修改,如果启发式算法不够好,A *与Dijkstra几乎相同
所以是的,保证A *找到最短的路径。
答案 2 :(得分:1)
有趣的是,尽管可接受的启发式方法在100%的时间内提供了最佳解决方案,但在某些情况下它们可能会很慢。如果有几条路径的总距离大致相同,则不可接受的启发式算法将在相对等效的路径之间提供更快的“决策”。请注意,您必须使用已关闭的列表(您已执行此操作)才能生效。
事实上,Pearl在他的“Heuristics”一书中证明,如果你的启发式算法被高估了一小部分,那么所提供的解决方案只会比同等数量(最多)的最佳解决方案更长!
对于某些快速/实时应用,这可以帮助提高速度,同时以较低的成本提高解决方案质量。