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

时间:2017-04-22 11:10:43

标签: algorithm

我目前正在接受我们的讲师在我们大学给我们的挑战。我们一直在研究最流行的寻路算法,如Dijkstra和A *。虽然,我认为这次挑战练习需要别的东西,而且让我感到难过。

需要解决的迷宫的直观表示:

Maze

色彩传奇
蓝色=起始节点
灰色=路径
绿色=目的地节点

它应该被解决的方式是,当移动完成时,必须完成它直到它与迷宫的边缘或障碍物(黑色边界)碰撞。它还需要以尽可能少的行移动来解决(在这种情况下为7)

我的问题:是否有人可以按照正确的方向推动我查看哪种算法?我认为Dijkstra / A *不是要走的路,考虑到最短的路径并不总是给出赋值的正确的路径。

3 个答案:

答案 0 :(得分:1)

Dijkstra / A *仍然可以解决,需要改变的是邻居的配置。

一点背景,第一:

Dijkstra和A *是在图上制定的一般路径寻找算法。当我们在网格上移动一个角色而不是图形时,图形的位置可能不那么明显。但它仍然存在,构建图形的一种方法如下:

  • 图表的节点对应于网格的单元格
  • 节点之间存在与相邻单元格对应的边缘。

实际上,在涉及它们之间的一些配置和转换的大多数问题中,可以构造相应的图形,并应用Dijkstra / A *。因此,还可以解决诸如sliding puzzlerubik's cube等问题,这些问题显然与在网格上移动的角色显着不同。但它们有状态,并且状态之间有转换,因此有可能尝试图搜索方法(这些方法,特别是像Dijkstra算法这样的不知情的方法,由于搜索空间很大,可能并不总是可行的,但是原则它可以应用它们。)

在您提到的问题中,图表与典型角色移动的图表没有太大区别:

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

正如Tamas Hegedus在评论部分所指出的那样,如果使用A *,应该选择启发函数是不明显的。

基于曼哈顿或欧几里德距离的标准启发法在这里无效,因为它们可能会高估与目标的距离。

一个有效的启发式方法是 id (row!= destination_row)+ id (col!= destination_col),其中 id 是身份函数, id (false)= 0且 id (true)= 1。

答案 1 :(得分:0)

Dijkstra / A *很好。您需要的是仔细考虑您认为图形节点和图形边缘的内容。

站在蓝色单元格(让我们称之为5,5),你有三个有效的动作:

  • 向右移动一个单元格(到6,5

  • 向左移动四个单元格(到1,5

  • 向上移动五个单元格(到5,1

请注意,您无法5,5转到4,55,4。将相同的推理应用于新节点(例如,从5,1,您可以转到1,110,15,5),您将获得运行Dijkstra /的图表A *。

答案 2 :(得分:0)

您需要评估每个可能的移动并采取最小距离的移动。如下所示:

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()调用:

  minDistance(x + 1, y + 1, distance),  // go up diagonally to right
  minDistance(x - 1, y - 1, distance),  // go down diagonally to left
  minDistance(x + 1, y - 1, distance),  // go up diagonally to left
  minDistance(x - 1, y + 1, distance),  // go down diagonally to right