今天在一次考试中我得到了一个算法问题,我得到了棋盘的N * M大小,我应该确定一个骑士可以从左下边缘做的最小可能移动次数是多少。棋盘走向右边缘。怎么办?
答案 0 :(得分:2)
使用BFS和memoization的解决方案:
# Memoization
memo = a matrix of NOVISITED of size N x M
# Starting position
# (row, column, jumps)
queue.push((0, 0, 0))
while queue is not empty:
# Get next not visited position
row, column, jumps = queue.pop()
# Mark as visited
memo[row][column] = jumps
for each possible move (nrow, ncolumn) from (row, column):
if memo[nrow][ncolumn] is NOVISITED:
# Queue next possible move
queue.append((nrow, ncolumn, jumps + 1))
如果我们将可能的距离视为非负数NOVISITED
,则 -1
可以具有值null
或[0,+inf)
。
memo[row][column]
可以访问每个方块的最小跳转次数,因此左下角右上角的答案位于memo[N - 1][M - 1]
。
<强>更新强>
请注意,如果矩阵是方形N x N
,则可以应用对称原则。
答案 1 :(得分:1)
我相信你可以将此减少到三种情况:
你有一块没有解决方案的电路板:2w * 4h
您的电路板解决方案为1:2w * 3h
你有一个正方形的板,因此有一个4:3w * 3h的解决方案
如果您的电路板大于这些电路板,您可以通过将一个移动的端点设置为较大电路板的起点来将其减小为其中一个电路板。
示例:尺寸为4w * 5h的电路板:
_ _ _ _
_ _ _ _
_ e _ _
_ _ _ _
s _ _ _
其中s是开始,e是结束。
从那里,将它减少到方板:
_ 1 e
3 _ _
s _ 2
需要4步才能到达终点。所以你有1 + 4次移动= 5这个大小。
我希望这足以让你开始。
编辑:这似乎并不完美。但是,它演示了一种解决此问题的启发式方法。以下是您观看乐趣的另一个案例:
_ _ _ e
_ 3 _ _
_ _ _ _
_ _ 2 _
_ _ _ _
_ 1 _ _
_ _ _ _
s _ _ _
在4x8电路板上有4次移动直到最后。
通过编程语言,可以通过从当前位置映射所有可能的移动并查看它们是否与终点匹配来更好地解决这个问题。如果他们不这样做,请检查您的问题现在是否已经解决过。正如评论者指出的那样,这是通过备忘录完成的。
但是,如果您是手动执行此操作,我敢打赌,您可以通过将其分解为少量案例来解决这个问题。
答案 2 :(得分:1)
您可以使用BFS或DFS模拟骑士的移动。我个人更喜欢DFS方法,因为它可以递归地实现。如果你有一个函数process
,它将当前x位置,当前y位置,表格行,表格列和计数器作为参数,解决方案将如下所示:
/* .......... */
process(x-1, y-2, R, C, count+1);
process(x+1, y-2, R, C, count+1);
process(x-2, y-1, R, C, count+1);
process(x-2, y+1, R, C, count+1);
process(x-1, y+2, R, C, count+1);
process(x+1, y+2, R, C, count+1);
process(x+2, y-1, R, C, count+1);
process(x+2, y+1, R, C, count+1);
/* .......... */
当您到达目的地时,您将返回当前的计数值。
编辑:它也可以使用动态编程解决。您将dp(i,j)
定义为到达广场(i,j)的最佳方式。所以dp(i,j)等于:
dp(i,j) = min{dp(all squares that can reach (i,j) in one move)} + 1
答案 3 :(得分:1)
这是有效的解决方案。
首先,特殊情况。如果n = 1
您无法跳转,则该问题仅适用于(1, 1)
。如果通过检查n = 2
,您只能选择一条路径,只有m = 4k + 3
2k + 1
才能解决问题,在这种情况下您需要m = 1,2
跳转才能到达目的地。如果r, l, u, d
,则反之亦然。
现在一般情况。骑士有8次可能的跳跃,它在一个方向上变为2,然后在另一个方向上变为1。可能的方向是nru
(向右,向左,向上,向下)。因此,让n - 1 = 2*nru + nur - nul - 2*nlu - 2*nld - ndl + ndr + 2*nrd
m - 1 = nru + 2*nur + 2*nul + nlu - nld - 2*ndl - 2*ndr - nrd
成为它向右跳2次然后向上跳1次的次数,同样对于其他7次跳跃也是如此。那么答案必须是以下一对方程的解决方案:
nru + nur + nul + nlu + nld + ndl + ndr + nrd
跳跃的次数是:
2 < n
我们希望跳跃次数尽可能低。直观地说,如果我们有一组满足前两个方程的数字,并且我们已经将跳跃次数设置得很低,那么我们就不应该在找到一个将跳跃停留在框内的命令时遇到很多麻烦。我不会证明这一点,但如果2 < m
和m < n
,则证明这是真的。
因此解决了这个整数规划问题(解决了保持跳跃次数尽可能低的那两个方程式),我们得到了答案。有解决方案,但这个特殊问题非常简单。我们只是做“明显的事情”来接近我们的目标,找出几个额外的跳跃,并且不难证明这是整数方程的最优解,因此必须是国际象棋的答案问题
那么显而易见的是什么?首先,如果n < m
,我们可以翻转一下,所以我们可以假设{{1}}而不失一般性。 (董事会至少离你一样远,就像它横向一样。)鉴于这一事实,显而易见的事情是向上跳,直到你撞到墙上,或者你从对角线向下伸展你想要的角落。此时,您沿着墙壁或对角线朝目标前进。
如果你直接降落在目标上,你会得到最好的答案。
如果你沿着墙壁走过并错过了1,事实证明,通过将你的一个跳跃转换成一对,你可以在你需要的地方结束。如果你沿着墙走了2并错过了(即你是一个对角线),那么你需要插入2个跳跃。 (距离显示您至少还需要一个,并且一个简单的奇偶校验参数显示您至少需要2个,并且一对跳跃将执行此操作。)
如果你沿着对角线走了1并且错过了1,那么插入一对跳跃就可以了。
如果你沿着对角线走过并错过了2,那么将右上/右上对转换为右上/右上/左上/左上你可以再做2个以上跳跃。
如果你没有沿着对角线行进但是有一个左上角,将其转换为右上/左上/右上三联,再次你可以再跳2次。
剩下的特殊情况是3x3板,需要4次跳跃。
(我留给你来弄清楚图片适用的所有适当的不等式和模数。)