英文:
What breaks tie when using A* for 8 puzzle solver
问题
我正在使用曼哈顿距离和自初始棋盘以来的移动次数来确定优先级。经常出现多个可能的下一个棋盘具有相同的优先级,优先队列如何知道选择哪一个?当我第一次尝试制作求解器时,它总是选择了错误的棋盘。我在GitHub上找到了一些代码,它使用了与我的相同逻辑,但那段代码总是选择正确的棋盘,它的compareTo函数中没有任何不同的内容来进行决定。现在我重新开始了,做了类似GitHub代码的事情,现在它可以工作了,但我不知道为什么。有人知道是什么造成了差异吗?
这是算法的基础:
minSearchNode = pq.delMin();
for(Board neighbour : minSearchNode.board.neighbors()){
if(minSearchNode.moves == 0){
pq.insert(new SearchNode(neighbour, minSearchNode.moves + 1, minSearchNode));
}
else if(!neighbour.equals(minSearchNode.previous.board)){
pq.insert(new SearchNode(neighbour, minSearchNode.moves + 1, minSearchNode));
}
}
我曾经在某处读到,A*算法一次错误的选择并不重要,因为它是启发式的,它会在后来找到正确的解决方案。但如果程序总是在选择下一个棋盘时做出错误的选择,那么它将尝试数百万种组合。
英文:
I am using manhattan distance + moves since the initial board for priority. It often happens that more possible next boards have same priority, how does the priority queue know which one to choose? When I first tried making solver it always chose wrong board. I found code on github and it used same logic as mine but that code always chose right one, he didn't have anything different in compareTo function what would do tie break. Now I started again and I've done something similar to github code and now it works and I don't know why. Does anyone have any idea what could have made difference?
This is basis of algorithm
minSearchNode = pq.delMin();
for(Board neighbour : minSearchNode.board.neighbors()){
if(minSearchNode.moves == 0){
pq.insert(new SearchNode(neighbour, minSearchNode.moves + 1, minSearchNode));
}
else if(!neighbour.equals(minSearchNode.previous.board)){
pq.insert(new SearchNode(neighbour, minSearchNode.moves + 1, minSearchNode));
}
}
I've read somewhere that it doesn't matter if A* does one wrong choice because it is heuristic and it will find the right solution later. Well it wouldn't program would just try millions of combinations and always choose wrong next board in tie break
答案1
得分: 1
I don't know what you were doing wrong at first, so I can't guess what changed to make the result correct. But what you read is right.
首先,一个优先队列如何解决优先级相等的情况在很大程度上取决于实现方式。通常的实现是使用堆。但使用DEQ也有一些优点。不管哪种方式,你只能确保下一个最小值是最小的,但不知道具体是哪一个。
至于"pick wrong",一旦你需要执行类似回溯的操作,以寻找更糟糕的启发式解,搜索将切换其关注点。然后它将尝试其他方式,带有回溯。如果启发式有效,这意味着它会一直找到有前途的路径,直到找到一个好的路径。如果启发式没有证明有效,它可能面临指数级增长。
其次,大多数A*算法的实现会跟踪它已经到达的节点。通常情况下,会找到到达同一节点的多条路径,但只有一条最好的路径会被保留。拒绝重新访问节点可以控制搜索空间,并使查找最佳路径变得更容易。但对于搜索非常庞大的图形可能是不切实际的。
第三,我有时发现将优先级设置为一个简单的数字并不是很有用。相反,可以将其设置为一对,例如(cost + heuristic, -cost)
。这样做的目的是根据我们对路径质量的估计进行优先排序,然后按照我们已经探索的距离进行排序。这意味着如果有多条同样好的路径,我们会首先探索其中一条直到结束,然后再切换到其他路径。这可能会显著影响你探索的空间。
英文:
I don't know what you were doing wrong at first, so I can't guess what changed to make the result correct. But what you read is right.
First, how a priority queue breaks ties is very much implementation dependent. The usual implementation is a heap. But there are advantages to using a DEQ instead. Either way you're only guaranteed that the next minimum is a minimum, but not which ones.
As for the "pick wrong", the search will switch what it is focused on as soon as you have to do anything that looks like a backtrack to something that is worse for the heuristic. Then it will try something else with a backtrack. If the heuristic is useful, this means that it keeps finding promising things to track until it finds a good route. If the heuristic does not prove useful, it can indeed face an exponential explosion.
Second, most A* implementations will keep track of the places it has reached. It is common to find multiple routes to the same node, but only the best one can wind up being best. Refusing to revisit nodes controls the search space and makes it easier to find the best route. But for searching a very large graph it may be prohibitive.
Third, I sometimes find it useful to have the priority NOT be a simple number. Instead make it a pair like (cost + heuristic, -cost)
. (This can be done in various ways.) What this does is prioritize by our estimate of how good the route is, and then prioritize by how far we've explored. This means that if there are multiple equally good paths, we'll explore whichever one we try first to the end before switching to the others. This can make a significant difference in how much of the space you explore.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论