Algorithm 解决这个迷宫的最佳算法?
我现在被困在我们大学讲师给我们的一个挑战中。我们一直在研究最流行的寻路算法,如Dijkstra和A*。尽管如此,我认为这个挑战性练习还需要一些别的东西,这让我感到困惑 需要解决的迷宫的视觉表示:Algorithm 解决这个迷宫的最佳算法?,algorithm,Algorithm,我现在被困在我们大学讲师给我们的一个挑战中。我们一直在研究最流行的寻路算法,如Dijkstra和A*。尽管如此,我认为这个挑战性练习还需要一些别的东西,这让我感到困惑 需要解决的迷宫的视觉表示: 颜色图例 蓝色=起始节点 灰色=路径 绿色=目标节点 解决这个问题的方法是,当移动完成时,必须一直移动到与迷宫边缘或障碍物(黑色边界)碰撞为止。还需要以尽可能少的行移动量解决此问题(在本例中为7) 我的问题是:有人能把我推到正确的方向上看什么算法吗?我认为Dijkstra/A*不是应该走的路,考虑到
颜色图例
蓝色=起始节点
灰色=路径
绿色=目标节点 解决这个问题的方法是,当移动完成时,必须一直移动到与迷宫边缘或障碍物(黑色边界)碰撞为止。还需要以尽可能少的行移动量解决此问题(在本例中为7)
我的问题是:有人能把我推到正确的方向上看什么算法吗?我认为Dijkstra/A*不是应该走的路,考虑到最短路径并不总是分配给作业的正确路径。Dijkstra/A*可以。您需要仔细考虑图形节点和图形边缘。 站在蓝色单元格中(我们称之为
5,5
),您有三个有效的移动:
- 向右移动一个单元格(至
)6,5
- 向左移动四个单元格(至
)1,5
- 向上移动五个单元格(至
)5,1
请注意,您不能从
5,5
转到4,5
或5,4
。将同样的推理应用于新节点(例如从5,1
你可以转到1,1
,10,1
和5,5
),你会得到一个运行Dijkstra/a*的图,Dijkstra/a*仍然可以解决,需要改变的是邻居的配置
一点背景,首先: Dijkstra和A*是基于图的通用路径查找算法。当角色在网格上移动而不是图形时,图形所在的位置可能不太明显。但它仍然存在,构建图形的一种方法是:
int minDistance(int x, int y, int prevX, int prevY, int distance) {
if (CollionWithBorder(x, y) // can't take this path
return int.MAX_VALUE;
if (NoCollionWithBorder(x, y) // it's OK to take this path
{
// update the distance only when there is a long change in direction
if (LongDirectionChange(x, y, prevX, prevY))
distance = distance + 1;
)
if (ReachedDestination(x, y) // we're done
return distance;
// find the path with the minimum distance
return min(minDistance(x, y + 1, x, y, distance), // go right
minDistance(x + 1, y, x, y, distance), // go up
minDistance(x - 1, y, x, y, distance), // go down
minDistance(x, y - 1, x, y, distance)); // go left
}
bool LongDirectionChange(x, y, prevX, prevY) {
if (y-2 == prevY && x == prevX) ||(y == prevY && x-2 == prevX)
return true;
return false;
}
- 图形的节点对应于网格的单元
- 与相邻单元对应的节点之间存在边
在您提到的问题中,图形与具有典型角色移动的图形差别不大:
- 节点仍然可以是网格的单元
- 现在,从一个节点到另一个节点的边将对应于有效移动(在边界或障碍物附近结束),在这种情况下,这些边并不总是与网格单元的四个空间近邻重合
正如Tamas Hegedus在评论部分所指出的,如果使用*的话,应该选择什么样的启发式函数并不明显 基于曼哈顿距离或欧几里德距离的标准启发式算法在这里无效,因为它们可能会高估到目标的距离
一个有效的启发式方法是id(行!=目的地行)+id(列!=目的地列),其中id是标识函数,id(假)=0,id(真)=1。您需要评估每一个可能的移动,并采取最小距离的移动。如下所示:
int minDistance(int x, int y, int prevX, int prevY, int distance) {
if (CollionWithBorder(x, y) // can't take this path
return int.MAX_VALUE;
if (NoCollionWithBorder(x, y) // it's OK to take this path
{
// update the distance only when there is a long change in direction
if (LongDirectionChange(x, y, prevX, prevY))
distance = distance + 1;
)
if (ReachedDestination(x, y) // we're done
return distance;
// find the path with the minimum distance
return min(minDistance(x, y + 1, x, y, distance), // go right
minDistance(x + 1, y, x, y, distance), // go up
minDistance(x - 1, y, x, y, distance), // go down
minDistance(x, y - 1, x, y, distance)); // go left
}
bool LongDirectionChange(x, y, prevX, prevY) {
if (y-2 == prevY && x == prevX) ||(y == prevY && x-2 == prevX)
return true;
return false;
}
这是假设不允许对角移动。如果是,请将它们添加到min()调用:
它是。您的示例显示了7条边,每条边的成本为1。您将使用什么样的启发式函数?@TamasHegedus问得好,标准启发式(基于曼哈顿,欧几里德距离)在这里无效,因为它们会高估到目标的距离。一个有效的选择是id(row!=目的地_row)+id(columnn!=目的地_column),其中id是id(true)=1,id(false)=0的标识函数。我不认为这是非常有用的,但它是有效的,也许比不提供信息要好一点。我会继续思考:)如果你有什么想法(或者应该单独问另一个问题),请告诉我。您好,我尝试用给定的启发式公式来实现这个想法,虽然它对这个迷宫示例有效,但对其他示例无效。你有没有考虑过一种可能适用于任何迷宫的启发式方法您好,是的,启发式应该适用于任何迷宫,可能错误在其他地方。您也可以尝试将启发式设置为0,这也是有效的(尽管这不是很有趣,使*的行为与Dijkstra的算法一样),只是为了测试——在这种情况下*是否仍然存在问题?@qwertyman这里有另一个迷宫:我添加了橙色的边,蓝色是起始节点,绿色是目标节点。。我还为起始节点的边添加了F成本。正如您所提到的,H成本正在计算中。G-cost I保持不变:目标节点与边缘和起始节点之间的距离(getTarget().distance(destination))。有什么想法吗?这对于典型情况来说是正确的,但是在这里提出的具体问题中,代理沿着单个行/列长距离移动(直到第一个障碍物)会产生一个单位的成本。是的,你是对的。我编辑了代码,以更改在沿行或列移动时如何增加距离。