【问题标题】:Finding the smallest number of steps between two points?找到两点之间的最小步数?
【发布时间】:2015-01-23 09:02:55
【问题描述】:

我有一个网格,网格有两个“材料”-

  • 地板

例如:

在这个网格中,我们有具有大小和位置的对象(对象的位置是左上角)。

在每个对象上我们可以做一些动作,比如 -

  • 向上移动
  • 向下移动
  • 向左移动
  • 向右移动
  • 转动对象(相对于左上角)

我需要创建一个函数来返回我需要对一个对象执行的最小操作量,以便将它从一个点移动到另一个点(我只需要操作量)。

我使用dijkstra's algorithm 解决了这个问题,但没有转弯动作

那么任何人都可以帮助我构建这个功能。

问题示例 -

  • 起点——

  • 终点

而且我需要返回我需要对一个对象执行的最少操作量。

【问题讨论】:

  • 哪种语言(c++,c,vb.net,java,c#)并不重要
  • 提示:考虑您的对象在任何时间点的状态。除了通常的 (x, y) 坐标之外,您还需要记录什么?四个方向移动每个都改变状态的 x 或 y 坐标;转弯会改变什么?
  • 转弯移动会像这样改变物体的大小 - Size = Reverse(CurrenSize), Height=Width and Width=Height
  • 我的意思是:不要再将图中的顶点视为字面上代表迷宫中的所有位置;它们代表对象可以处于的所有可能的状态。对象状态的一部分是它的(左上角的)位置,但这不是它的全部 .
  • 你能告诉我们更多关于动作的细节:除了方向,你能移动多少?它是固定的吗(例如向左移动 -> 将左上角的x 位置增加lambda)?旋转也是如此。我们有哪些选择?这将是“k.q° 的任何旋转,其中 k 是整数,q 是固定常数。因此问题变成:什么是 q?

标签: java vb.net algorithm graph-algorithm


【解决方案1】:

将问题视为在 3D 网格中寻找最短路径,深度为 2(每种可能的状态:水平和垂直)。您必须编写禁止从一个深度移动到另一个深度的约束,例如,如果不适合这种方式,则不能垂直。

现在您可以使用常规 BFS 来查找网格中的最短路径(即未加权图)。

【讨论】:

    【解决方案2】:

    对于您的问题,我认为 BFS 仍然有效。

    使用BFS解决传统迷宫问题,从头开始,你要:

    1. Enqueue every point that is accessible (not a piece of wall, and not visited) and connected to the current point.
    2. Dequeue current point and mark it as VISITED.
    

    从上面可以看出,BFS 不会让任何点被访问两次,从而避免了循环。

    你的问题

    至于你的问题,BFS 还是可以的,但是我们会稍微改变一下“可访问”的定义:

    首先,我将介绍“迷宫”矩阵的样子。 以下是下图中数字的含义。

    (假设物体大小为1*2,移动时物体的左上角停留在每一点)。

    00: The point can't be accessed, neither the object is horizontal nor vertical. 
    10: The point can be accessed if the object is horizontal
    01: The point can be accessed if the object is vertical
    11: The point can be accessed if the object is either horizontal or vertical
    

    您的图表可以转换为如下矩阵:

    将那些无法访问的点填上00,你会得到

    这更像是一个迷宫问题,但有点不同。

    最后,让我们看看如何“访问”这些点:

    connected 的定义类似于传统的迷宫问题。下面是一些例子:

    ---------
    | 01| 10|
    |---|---|
    | 10|   |
    ---------    (Not Connected from top-left to either top-right or bottom-left)
    
    
    ---------
    | 11| 10|
    |---|---|
    | 01|   |
    ---------    (Connected from top-left to both top-right and bottom-left)
    
    
    ---------
    | 10| 10|
    |---|---|
    | 01|   |
    ---------    (Connected from top-left to top-right, but not connected to bottom-left)
    

    所以剩下的可能很简单。遵循传统的 BFS 方法,创建一个二维数组来存储每个点的最短路径的长度。出队获取当前点,将当前点的connected邻居加入队列,并将此点标记为已访问,则一切都和BFS一样。

    得到最短路径后,重新运行程序,保持对象在当前点是垂直还是水平的状态,并模拟您在图像上的移动。仅在必要时添加转弯,您将获得添加转弯的结果。

    【讨论】:

      【解决方案3】:

      如果我明白您的要求,写出来会花费很长时间,但我能想到的最简单的方法是先找到路径,检查沿该路径的碰撞,旋转并添加动作相应地。

      • 使用基本的路径算法寻找到终点的路径。
      • 将路径节点存储在某种可遍历数组中(如果路径算法良好/简单,则总共应为 4 个)。
      • 尝试遵循路径注释(i 到数组计数)
      • 检查每个动作的碰撞。
      • (do while)如果可移动物体与墙壁相交,请旋转 90 度并重试。
      • (下一步)如果成功,保存到移动操作列表(移动 x/y,旋转 z)
      • 返回操作计数

      使用更复杂的网格,这显然会变得更复杂,但你只需要做 90 度转弯。大约 9 个动作应该是可能的。

      【讨论】:

        【解决方案4】:

        使用Breadth-first search 策略,根据是否必须转动物体为边缘分配权重。

        【讨论】:

        • 这个方法有个问题,因为在搜索中我们会陷入循环,像Move Up,Down,Up,Down....
        • 这行不通,因为您不知道对象当前的方向——也可能是。 -1.
        • 比这复杂得多,旋转对象的能力意味着对象可以在同一位置处于不同的状态。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-10
        • 1970-01-01
        • 2021-03-22
        • 1970-01-01
        • 1970-01-01
        • 2011-01-09
        • 2021-10-24
        相关资源
        最近更新 更多