我正在编写一个可以解决Java中8数码问题的A*算法,到目前为止,我已经实现了DFS、BFS、A*,使用的是错位的瓷砖数量,现在我只需要使用曼哈顿距离的启发式来实现它。
您可能知道,曼哈顿距离是每个瓷砖相对于其当前位置和目标状态中索引的位移之和。
我在谷歌上搜索并找到了这些Stack Overflow话题:
这些话题返回了以下代码:
int manhattanDistanceSum = 0;for (int x = 0; x < N; x++) // x-dimension, traversing rows (i) for (int y = 0; y < N; y++) { // y-dimension, traversing cols (j) int value = tiles[x][y]; // tiles array contains board elements if (value != 0) { // we don't compute MD for element 0 int targetX = (value - 1) / N; // expected x-coordinate (row) int targetY = (value - 1) % N; // expected y-coordinate (col) int dx = x - targetX; // x-distance to expected coordinate int dy = y - targetY; // y-distance to expected coordinate manhattanDistanceSum += Math.abs(dx) + Math.abs(dy); } }
这是我不理解的地方,给定这个棋盘和这个目标状态:
初始棋盘:
1,2,5 3,0,4 6,7,8
目标状态:
0,1,23,4,56,7,8
如果我输入board[0][0]的值为1,它恰好距离正确位置1步,我得到这些结果:
x = 0; y = 0; value = 1; targetX = (value -1)/3; // 0/3 = 0 targetY = (value -1)%3 //0%3 = 0 int dx = x - targetX; // 0 - 0 int dy = y - targetY; // 0 - 0 manhattanDistanceSum += Math.abs(dx) + Math.abs(dy);
这最终产生了0 + 0,这显然是不正确的,因为它应该返回值1。
是否有其他方法,例如:
for(int i = 0; i < 3 i ++){ for(int j =0; j < 3; j ++){ int value = currentBoard[i][j]; int goalValue = getLocationOfValueInGoalState(value); /* 计算该值与返回的目标状态位置的X距离,然后对Y做同样的事情 */ } }
希望有人能理解我的问题,老实说,我现在有点困惑。
回答:
您和您查看的参考实现之间的目标状态看起来有一点细微的差别。
对于参考实现,如果目标状态看起来像这样,它是有效的:
1 2 34 5 67 8 0
在您的情况下,您想要的是这个目标状态的曼哈顿距离:
0 1 23 4 5 6 7 8
一个快速的解决方法是简单地将您的目标状态重新定义为前者。
但是,如果您真正想要的是后者,那么请更改targetX/Y,不要从value中减去1。