最短路径的数量

时间:2016-09-21 04:42:57

标签: python algorithm chess

问题在于:

考虑到输入n = 4 x = 5,我们必须想象一个棋盘横跨(x轴)和5个正方形高(y轴)4个方格。 (此输入会发生变化,直到n = 200 x = 200)

然后,我们被要求确定从板上左下方块到板上右上方的最小最短路径(骑士可以在一个轴上移动2个空格,然后在另一个轴上移动1个空格)轴)。

我目前的想法:

使用2d数组存储所有可能的移动,执行广度优先 在2d数组上搜索(BFS)以找到最短路径。

Floyd-Warshall最短路径算法。

创建一个邻接列表并对其执行BFS(但我认为这样效率很低)。

说实话,虽然我对逻辑没有真正的把握。

任何人都可以帮助我使用psuedocode,python代码,甚至只是对问题进行逻辑演练吗?

4 个答案:

答案 0 :(得分:4)

BFS对于这个问题是足够有效的,因为它的复杂性是O(n * x),因为你只探索每个细胞一次。为了保持最短路径的数量,你只需要保留一个辅助数组来保存它们。

您也可以使用A *来更快地解决这个问题,但在这种情况下没有必要,因为这是编程竞赛的问题。

dist = {}
ways = {}

def bfs():
    start = 1,1
    goal = 6,6

    queue = [start]
    dist[start] = 0
    ways[start] = 1

    while len(queue):
        cur = queue[0]
        queue.pop(0)
        if cur == goal:
            print "reached goal in %d moves and %d ways"%(dist[cur],ways[cur])
            return

        for move in [ (1,2),(2,1),(-1,-2),(-2,-1),(1,-2),(-1,2),(-2,1),(2,-1) ]:
            next_pos = cur[0]+move[0], cur[1]+move[1]
            if next_pos[0] > goal[0] or next_pos[1] > goal[1] or next_pos[0] < 1 or next_pos[1] < 1:
                continue
            if next_pos in dist and dist[next_pos] == dist[cur]+1:
                ways[next_pos] += ways[cur]
            if next_pos not in dist:
                dist[next_pos] = dist[cur]+1
                ways[next_pos] = ways[cur]
                queue.append(next_pos)

bfs()

输出

reached goal in 4 moves and 4 ways

请注意,达到目标的方式数量会呈指数级增长

答案 1 :(得分:1)

我建议:

  1. 从目标位置向后使用BFS来计算(仅在O(nx)总时间内)骑士从彼此的方位中移动的目标(x,n)的最小距离。对于每个起始方块(i,j),将此距离存储在d [i] [j]。
  2. 计算c [i] [j],从(i,j)开始到目标(x,n)结束的最小长度路径的数量,递归地如下:
    • c [x] [n] = 1
    • c [i] [j] =所有(p,q)的c [p] [q]之和,
      • (p,q)是(i,j)和
      • 的骑士移动邻居
      • d [p] [q] = d [i] [j] -1。
  3. 在步骤2中使用memoisation以防止递归呈现指数时间。或者,您可以使用略微修改的第二个BFS(也是向后)计算c [] []自下而上,如下所示:

    c = x by n array with each entry initially 0;
    seen = x by n array with each entry initially 0;
    s = createQueue();
    push(s, (x, n));
    
    while (notEmpty(s)) {
        (i, j) = pop(s);
        for (each location (p, q) that is a knight's-move-neighbour of (i, j) {
            if (d[p][q] == d[i][j] + 1) {
                c[p][q] = c[p][q] + c[i][j];
                if (seen[p][q] == 0) {
                    push(s, (p, q));
                    seen[p][q] = 1;
                }
            }
        }
    }
    

    这里的想法是在计算具有较大距离的位置的任何c [] []值之前始终计算与目标具有一定距离的所有位置的c [] []值,因为后者取决于前者

    最短路径的长度为d [1] [1],这种最短路径的数量为c [1] [1]。 总计算时间为O(nx),这在渐近的意义上显然是最好的。

答案 2 :(得分:0)

尝试一下。绘制以下尺寸的电路板:1x1,2x2,3x3,4x4,以及一些奇数电路板,如2x4和3x4。从最小的板开始并且工作到最大,从左下角开始写0,然后找到从零开始的所有移动并写入1,从1找到所有移动并写入2,等等。直到有没有更多可能的举动。

对所有6个板子做了这个之后,你应该注意到一个模式:在你有一个更大的板子之前,有些方块无法移动,但是一旦一个方块被“发现”(即可以到达),这个数字对于所有不小于首次发现的电路板的电路板,该方块的最小移动量是恒定的。 (较小意味着小于n OR小于x,不小于(n * x))

这讲述了一些有力的,有趣的。所有方块都有一个必须与之相关的数字。这个数字是正方形的属性,而不是板,不依赖于板的大小/形状。这总是如此。但是,如果无法达到方格,则显然该数字不适用。

因此,您需要找到200x200电路板上每个方块的数量,并且您需要一种方法来查看电路板是否是另一个电路板的子集,以确定方块是否可达。

请记住,在这些编程挑战中,一些非常难的问题可以通过使用查找表在O(1)时间内解决。我不是说这个可以,但记住这个伎俩。对于这个,预先计算200x200板号并将它们保存在阵列中可以节省大量时间,无论是在首次运行时只运行一次还是在提交之前运行,然后结果都是硬编码的。

如果问题需要移动序列而不是移动次数,那么这个想法是一样的:用数字保存移动序列。

答案 3 :(得分:0)

我对这个问题的处理方法是回溯,因为x轴和y轴的方格数不同。

注意:对于某些情况,回溯算法可能会很慢,而对于其他情况则很快

为棋盘创建一个二维数组。你知道凝视指数和最终指数。要达到最终指数,你需要保持接近加入两个指数的对角线。

从起始索引看到骑士可以前往的所有索引,选择最接近对角线索引的索引并继续遍历,如果没有办法再往前走一步并移动到下一步从那里可以找到位置。

PS:这有点类似于一个众所周知的问题骑士之旅,其中选择任何起点你必须找到骑士覆盖所有方格的路径。我将此代码编写为java gui应用程序,如果您需要任何帮助,我可以将链接发送给您

希望这会有所帮助!!