问题在于:
考虑到输入n = 4 x = 5,我们必须想象一个棋盘横跨(x轴)和5个正方形高(y轴)4个方格。 (此输入会发生变化,直到n = 200 x = 200)
然后,我们被要求确定从板上左下方块到板上右上方的最小最短路径(骑士可以在一个轴上移动2个空格,然后在另一个轴上移动1个空格)轴)。
我目前的想法:
使用2d数组存储所有可能的移动,执行广度优先 在2d数组上搜索(BFS)以找到最短路径。
Floyd-Warshall最短路径算法。
创建一个邻接列表并对其执行BFS(但我认为这样效率很低)。
说实话,虽然我对逻辑没有真正的把握。
任何人都可以帮助我使用psuedocode,python代码,甚至只是对问题进行逻辑演练吗?
答案 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)
我建议:
在步骤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应用程序,如果您需要任何帮助,我可以将链接发送给您
希望这会有所帮助!!