Algorithm 解决这个迷宫的最佳算法?

Algorithm 解决这个迷宫的最佳算法?,algorithm,Algorithm,我现在被困在我们大学讲师给我们的一个挑战中。我们一直在研究最流行的寻路算法,如Dijkstra和A*。尽管如此,我认为这个挑战性练习还需要一些别的东西,这让我感到困惑 需要解决的迷宫的视觉表示: 颜色图例 蓝色=起始节点 灰色=路径 绿色=目标节点 解决这个问题的方法是,当移动完成时,必须一直移动到与迷宫边缘或障碍物(黑色边界)碰撞为止。还需要以尽可能少的行移动量解决此问题(在本例中为7) 我的问题是:有人能把我推到正确的方向上看什么算法吗?我认为Dijkstra/A*不是应该走的路,考虑到

我现在被困在我们大学讲师给我们的一个挑战中。我们一直在研究最流行的寻路算法,如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;
}
  • 图形的节点对应于网格的单元
  • 与相邻单元对应的节点之间存在边
实际上,在大多数涉及一些配置和它们之间的转换的问题中,可以构造相应的图,并应用Dijkstra/a*。因此,还可以解决诸如等问题,这些问题与网格上移动的角色明显不同。但是它们有状态和状态之间的转换,因此可以尝试使用图搜索方法(这些方法,特别是像Dijkstra算法这样的未知方法,由于搜索空间大,可能并不总是可行的,但原则上可以应用它们)


在您提到的问题中,图形与具有典型角色移动的图形差别不大:

  • 节点仍然可以是网格的单元
  • 现在,从一个节点到另一个节点的边将对应于有效移动(在边界或障碍物附近结束),在这种情况下,这些边并不总是与网格单元的四个空间近邻重合

正如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))。有什么想法吗?这对于典型情况来说是正确的,但是在这里提出的具体问题中,代理沿着单个行/列长距离移动(直到第一个障碍物)会产生一个单位的成本。是的,你是对的。我编辑了代码,以更改在沿行或列移动时如何增加距离。