曼哈顿距离过高估计让我发疯
Posted
技术标签:
【中文标题】曼哈顿距离过高估计让我发疯【英文标题】:Manhattan distance is over estimating and making me crazy 【发布时间】:2011-12-14 02:48:26 【问题描述】:我正在使用 Manhattan distance 实现 a-star 算法 来解决 8 谜题(在 C 中)。它似乎工作得很好,并且通过了很多单元测试,但在一种情况下它无法找到最短路径(它找到了 27 步而不是 25 步)。
当我将启发式函数更改为 Hamming distance 时,它分 25 步找到。 当我使曼哈顿距离函数返回实际成本的一半时,也可以在 25 个步骤中找到。
这就是为什么我认为问题出在曼哈顿距离函数的某个地方,并且过度估计了成本(因此不可接受)。我认为 C 程序中可能有其他问题,所以我编写了一个小 Python 脚本来测试和验证曼哈顿距离函数的输出,它们都产生完全相同的结果。
我真的很困惑,因为启发式函数似乎是唯一的失败点,而且它似乎同时是正确的。
您可以尝试this solver 并输入“2,6,1,0,7,8,3,5,4”这样的磁贴顺序 选择算法曼哈顿距离,它需要 25 个步骤。 现在改成曼哈顿距离+线性冲突,发现27步。
但我的曼哈顿距离(没有线性冲突)需要 27 步。
这是我的一般算法:
manhattan_distance = 0
iterate over all tiles
if the tile is not the blank tile:
find the coordinates of this tile on the goal board
manhattan_distance += abs(x - goal_x) + abs(y - goal_y)
我认为,如果某个重要部分出现非常严重的问题,它将无法通过之前的所有 25 次以上测试,因此这可能是某种边缘情况。
这里是 C 中的曼哈顿距离函数的注释:
int ManhattanDistance(Puzzle p, State b)
State goal = getFinalState(p);
int size = getSize(b);
int distance = 0;
if (getSize(goal) == size) // both states are the same size
int i, j;
for(i=0; i<size; i++)
for(j=0; j<size; j++) // iterate over all tiles
int a = getStateValue(b, i, j); // what is the number on this tile?
if (a != 'B') // if it's not the blank tile
int final_cordinates[2];
getTileCoords(goal, a, final_cordinates); // find the coordinates on the other board
int final_i = final_cordinates[0];
int final_j = final_cordinates[1];
distance += abs(i - final_i) + abs(j - final_j);
return distance;
请帮帮我。
编辑:正如在 cmets 中所讨论的,提供用于打开节点的代码可以在 here
找到【问题讨论】:
您的曼哈顿距离函数对我来说似乎很好..[嗯,至少从阅读它...] 你确定这是问题吗?也许您的 A* 实现在找到更短的路径时不会重新打开封闭节点?这可以解释为什么这个错误并不总是发生。 另请注意,如果size(goal) != size(b)
,则返回 0。无论如何都不应该发生这种情况,但是如果您已经检查过这种情况,您可能希望返回 infinity
[因为您无法获取到目标板尺寸不匹配的目标]
将您在此特定实例上的实现跟踪与另一个实现(例如code.google.com/p/a-star-algorithm-implementation)进行比较可能会很有用。查看它们的分歧点可以帮助您找到错误。
我同意阿米特,你的功能对我来说似乎很好。问题可能出在代码中的其他地方。尝试找到给您带来意外结果的最小情况并对其进行调试(即将预期的中间结果与实际结果进行比较)。
@amit 我已经检查了那些 if 块并且程序永远不会达到那些因为从一个州移动到另一个州的成本总是 1(而不是说,城市之间的道路长度)所以它永远不会需要重新打开一个关闭的节点,因为你走得越远,每一步的成本就会增加 1,所以你不可能找到一个你之前见过的节点,它的成本低于当前的移动。
【参考方案1】:
问题似乎不在于您的启发式函数,而在于算法本身。根据您对问题的描述,以及它仅在某些特定情况下发生的事实,我认为它与重新打开封闭顶点有关,一旦您找到了更好的路径。
在阅读您在 [cmets] 中提供的代码时,我想我理解了问题所在,在第 20 行:
if(getG(current) + 1 < getG(children[i]))
这是错误的!您正在检查g(current) + 1 < g(children[i])
,您实际上想要检查:f(current) + 1 + h(children[i]) < g(children[i])
,因为您想使用children[i]
的启发式函数而不是current
的启发式函数来检查这个值!
注意与设置f(children[i]) = minf(children[i]),f(current)+1
相同,然后加上h(children[i])
得到g
的值。
【讨论】:
感谢您检查该代码。我根本没有遵循你的逻辑。 f(current) = g(current) + h(current) 为什么要将 h(current) 和 h(children[i]) 加在一起并期望它小于 g(children[i])?如您所知,每个“h”值代表从该节点到目标的大致成本。另请查看wikipedia page 中的算法,该部分属于该代码中的“tentative_g_score”,它等于 g_score[x] + dist_between(x,y) 我不明白“h”在这里做什么?跨度>以上是关于曼哈顿距离过高估计让我发疯的主要内容,如果未能解决你的问题,请参考以下文章
R语言计算曼哈顿距离(Manhattan Distance)实战:计算两个向量的曼哈顿距离dist函数计算矩阵中两两元素的曼哈顿距离