如何使A*算法给出最短路径?(见随附图片)
How can I make the A* algorithm give me the shortest path? (see picture enclosed)
我使用了astar算法的Justin Heyes-Jones实现。我的启发式函数就是欧几里得距离。在所附的图形中(很抱歉质量不好)描述了一种特定情况:假设我们从节点1转到节点2。最短的方法是通过节点a-b-c-d-e。但欧几里得启发式的逐步Astar将为我们提供通过以下节点的方法:a-b’-c’-d’-e,我理解为什么会发生这种情况。但是我该怎么做才能让它返回最短的路径?!
astar 的伪最短路径查找
真正的路线图导入代码:
#include "search.h"
class ArcList;
class MapNode
{
public:
int x, y; // ���������� ����
MapNode();
MapNode(int X, int Y);
float Get_h( const MapNode & Goal_node );
bool GetNeighbours( AStarSearch<MapNode> *astarsearch, MapNode *parent_node );
bool IsSamePosition( const MapNode &rhs );
void PrintNodeInfo() const;
bool operator == (const MapNode & other) const;
void setArcList( ArcList * list );
private:
ArcList * list;
};
class Arc
{
public:
MapNode A1;
MapNode B1;
Arc(const MapNode & a, const MapNode & b);
};
class ArcList
{
public:
void setArcs( const std::vector<Arc> & arcs );
void addArc( const Arc & arc );
size_t size() const;
bool addNeighbours( AStarSearch<MapNode> * astarsearch, const MapNode & neighbour );
private :
std::vector<Arc> arcs;
};
std::vector <MapNode> FindPath(const MapNode & StartNode, const MapNode & GoalNode)
{
AStarSearch<MapNode> astarsearch;
astarsearch.SetStartAndGoalStates( StartNode, GoalNode );
unsigned int SearchState;
unsigned int SearchSteps = 0;
do
{
if ( SearchSteps % 100 == 0)
std::cout << "making step " << SearchSteps << endl;
SearchState = astarsearch.SearchStep();
SearchSteps++;
}
while ( SearchState == AStarSearch<MapNode>::SEARCH_STATE_SEARCHING );
std::vector<MapNode> S;
if ( SearchState == AStarSearch<MapNode>::SEARCH_STATE_SUCCEEDED )
{
int steps = 0;
for ( MapNode * node = astarsearch.GetSolutionStart(); node != 0; node = astarsearch.GetSolutionNext() )
{
S.push_back(*node);
// node->PrintNodeInfo();
}
astarsearch.FreeSolutionNodes();
}
else if ( SearchState == AStarSearch<MapNode>::SEARCH_STATE_FAILED )
{
throw " SEARCH_FAILED ";
}
return S;
}
函数FindPath为我提供了结果节点的矢量。
这里是addNeighbours方法:
bool ArcList::addNeighbours( AStarSearch<MapNode> * astarsearch, const MapNode & target )
{
assert(astarsearch != 0);
bool found = false;
for (size_t i = 0; i < arcs.size(); i++ )
{
Arc arc = arcs.at(i);
if (arc.A1 == target)
{
found = true;
astarsearch->AddSuccessor( arc.B1 );
}
else if (arc.B1 == target )
{
found = true;
astarsearch->AddSuccessor( arc.A1 );
}
}
return found;
}
和get_h方法:
float MapNode::Get_h( const MapNode & Goal_node )
{
float dx = x - Goal_node.x;
float dy = y - Goal_node.y;
return ( dx * dx + dy * dy );
}
我知道这不是精确的距离(这里不取平方根)——这样做是为了在评估时节省一些机器资源。
当您使用A*图搜索时,即您只考虑对节点的第一次访问,而忽略未来的访问,事实上,当您的启发式不一致时,可能会发生这种情况。如果启发式不一致,并且您使用图形搜索(您保留一个已访问状态的列表,如果您已经遇到一个状态,则不会再次展开它),则您的搜索不会给出正确的答案。
然而,当您使用具有可接受启发式的A*树搜索时,您应该得到正确的答案。树搜索和图搜索的区别在于,在树搜索中,每次遇到状态时都会展开它。因此,即使一开始算法决定采用更长的b',c',d'路径,但后来它会返回到a,再次展开它,并发现b,c,d路径实际上更短。
因此,我的建议是,要么使用树搜索而不是图搜索,要么选择一致的启发式方法。
关于一致性的定义,请参见例如:Wikipedia:A*搜索算法
编辑:虽然以上仍然是真的,但这种启发确实是一致的,我为造成的混乱道歉。
第二版:虽然启发式本身是可接受的和一致的,但实现不是。为了性能,你决定不做平方根运算,这使得你的启发式算法不可接受,这也是你得到错误结果的原因。
对于未来,最好先尽可能天真地实现您的算法。这通常有助于保持它们的可读性,并且它们不太容易出现错误。如果有漏洞,就更容易发现。因此,我的最后建议是,除非你需要,或者其他一切都很好,否则不要进行优化。否则你可能会遇到麻烦。
似乎在get_h方法中取平方根已经解决了这个问题。事实证明,我的启发式是不可接受的(至少我认为这可以解释它)。特别感谢Laky和justinhj的帮助!!!
- 内存效率表示最短路径的方法?
- 用于查找网格中最短路径的算法
- 查找最短路径算法
- BFS 打印最短路径
- 使用 Dijkstra 算法跟踪两个节点之间的最短路径
- 使用C++具有两个数字的最短路径算法.(C++)
- 使用迭代深度优先搜索算法的未加权图的最短路径
- 如何仅在 2 个节点之间获取最短路径,给定邻接列表有向图?
- 如何使用贝尔曼-福特算法返回所有具有捆绑重量的最短路径?
- 使用优先级队列查找所有与 Dijkstra 相同的最短路径
- 尝试在图形中查找最短路径时的无限循环
- C++计算有向图中的最短路径
- 使用BFS存储和打印最短路径
- 如何制作由原始图形的最短路径边组成的新图形
- 有没有一种方法可以使用弗洛伊德-沃歇尔算法给出最短路径,其中存在负权重循环而不允许重叠边缘?
- 加权图的开始和结束的最短路径
- 使 c++11 Dijkstra 实现返回最短路径
- 弗洛伊德最短路径算法C++
- Dijkstra 最短路径算法性能 std::p riority_queue VS std::set.
- 如何使A*算法给出最短路径?(见随附图片)