A *寻路保证找到最短路径?

时间:2011-09-11 19:25:06

标签: c++ artificial-intelligence path-finding

如果正确实施,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;
}

3 个答案:

答案 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”一书中证明,如果你的启发式算法被高估了一小部分,那么所提供的解决方案只会比同等数量(最多)的最佳解决方案更长!

对于某些快速/实时应用,这可以帮助提高速度,同时以较低的成本提高解决方案质量。