我正在尝试解决涉及国际象棋的算法问题。
假设我在A8中有一个国王并希望将其移至H1(仅允许移动)。 我怎样才能找出完成任何给定k移动的可能性(路径)的数量? (例如,如果我想通过15次移动将国王从A8移动到H1,会有多少路径/可能性?)
一个简单的解决方案是将其视为图形问题并使用任何标准 路径寻找算法将每个移动计算为有成本1.因此,假设我想将我的王从A8移动到H1以10个移动。我只想搜索总计10的所有路径。
我的问题是,如果还有其他更聪明有效的方法吗? 我也想知道,如果有更多的“数学”和直接的东西找到这个数字而不是那么“算法”和“蛮力似的”?
答案 0 :(得分:3)
您可以使用邻接矩阵。如果将这样的矩阵与其自身相乘,则可以获得从点到点的路径数量。例如:
图:完整的K3图:A - B - C -
矩阵:
[0 ; 1 ; 1]
[1 ; 0 ; 1]
[1 ; 1 ; 0]
长度为2的路径:M * M
[2 ; 1 ; 1]
[1 ; 2 ; 1]
[1 ; 1 ; 2]
长度3则为M * M * M
[2 ; 3 ; 3]
[3 ; 2 ; 3]
[3 ; 3 ; 2]
答案 1 :(得分:3)
这是一个直接的O(N ^ 3)动态编程问题。
只需按如下方式分配3D数组:
设Z [x] [y] [k]是从船上位置(x,y)到达目的地的k步的移动次数。
基本案例是:
foreach x in 0 to 7,
foreach y in 0 to 7,
Z[x][y][0] = 0 // forall x,y: 0 ways to reach H1 from
// anywhere else with 0 steps
Z[7][7][0] = 1 // 1 way to reach H1 from H1 with 0 steps
递归案例是:
foreach k in 1 to K,
foreach x in 0 to 7,
foreach y in 0 to 7,
Z[x][y][k+1] = Z[x-1][y][k]
+ Z[x+1][y][k]
+ Z[x][y-1][k]
+ Z[x][y+1][k]
+ ...; // only include positions in
// the summation that are on the board
// and that a king can make
你的回答是:
return Z[0][0][K]; // number of ways to reach H1(7,7) from A8(0,0) with K moves
(通过将移动分解为两组水平和垂直移动,然后将这些移动组合并乘以交错数量,可以更快地在O(n ^ 2)中执行此操作。)
请参阅此相关问题和答案:No of ways to walk M steps in a grid
答案 2 :(得分:0)
.......E <-end
........
........
........
........
........
........
S....... <-start
不幸的是,您无法使用“任何标准路径查找算法”,因为您的路径可能不是最短路径。你必须专门使用一个考虑所有路径的天真搜索(例如深度优先或广度优先)。
但是,因为您不关心如何到达磁贴,您可以使用一种称为动态编程的技术。对于每个位置(i,j), n 中的到达方式的数量会移动(让我们称之为方式 i,j (n))是:
方式 i,j (n)=方式 i-1,j (n-1)+种类 i + 1,j < / sub>(n-1)+种类 i,j-1 (n-1)+种类 i,j + 1 (n-1)+种 i + 1,j + 1 (n-1)+路 i-1,j + 1 (n-1)+路径 i + 1,j-1 (n-1)+种类 i-1,j-1 (n-1)
也就是说,国王可以从1个移动中的任何相邻方块移动:
方式 i,j (n)= sum neighbors(i,j)(方式 neighbor (n-1) )
因此你可以这样做,例如在python中:
SIZE = 8
cache = {}
def ways(pos, n):
r,c = pos # row,column
if not (0<=r<SIZE and 0<=c<SIZE):
# off edge of board: no ways to get here
return 0
elif n==0:
# starting position: only one way to get here
return 1 if (r,c)==(0,0) else 0
else:
args = (pos,n)
if not args in cache:
cache[args] = ways((r-1,c), n-1) + ways((r+1,c), n-1) + ways((r,c-1), n-1) + ways((r,c+1), n-1) + ways((r-1,c-1), n-1) + ways((r+1,c-1), n-1) + ways((r+1,c-1), n-1) + ways((r+1,c+1), n-1)
return cache[args]
演示:
>>> ways((7,7), 15)
1074445298
上述技术称为memoization,比动态编程更容易编写,因为您不需要真正考虑事务的顺序。当我们执行一系列越来越大的查询时,您可以看到缓存增长:
>>> cache
{}
>>> ways((1,0), 1)
1
>>> cache
{((1, 0), 1): 1}
>>> ways((1,1), 2)
2
>>> cache
{((0, 1), 1): 1, ((1, 2), 1): 0, ((1, 0), 1): 1, ((0, 0), 1): 0, ((2, 0), 1): 0, ((2, 1), 1): 0, ((1, 1), 2): 2, ((2, 2), 1): 0}
>>> ways((2,1), 3)
5
>>> cache
{((1, 2), 1): 0, ((2, 3), 1): 0, ((2, 0), 2): 1, ((1, 1), 1): 1, ((3, 1), 1): 0, ((4, 0), 1): 0, ((1, 0), 1): 1, ((3, 0), 1): 0, ((0, 0), 1): 0, ((2, 0), 1): 0, ((2, 1), 1): 0, ((4, 1), 1): 0, ((2, 2), 2): 1, ((3, 3), 1): 0, ((0, 1), 1): 1, ((3, 0), 2): 0, ((3, 2), 2): 0, ((3, 2), 1): 0, ((1, 0), 2): 1, ((4, 2), 1): 0, ((4, 3), 1): 0, ((3, 1), 2): 0, ((1, 1), 2): 2, ((2, 2), 1): 0, ((2, 1), 3): 5}
(在python中,也可以使用@cached
或@memoized
装饰器来避免在最后else:
块中编写整个代码。其他语言有其他方法可以自动执行memoization 。)
以上是一种自上而下的方法。它有时会产生非常大的堆栈(您的堆栈将随n
增长)。如果你想要超级高效以避免不必要的工作,你可以采用自下而上的方法,模拟国王的所有位置,分为1步,2步,3步,......:
SIZE = 8
def ways(n):
grid = [[0 for row in range(8)] for col in range(8)]
grid[0][0] = 1
def inGrid(r,c):
return all(0<=coord<SIZE for coord in (r,c))
def adjacentSum(pos, grid):
r,c = pos
total = 0
for neighbor in [(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1),(0,-1),(1,-1)]:
delta_r,delta_c = neighbor
(r2,c2) = (r+delta_r,c+delta_c)
if inGrid(r2,c2):
total += grid[r2][c2]
return total
for _ in range(n):
grid = [[adjacentSum((r,c), grid) for r in range(8)] for c in range(8)]
# careful: grid must be replaced atomically, not element-by-element
from pprint import pprint
pprint(grid)
return grid
演示:
>>> ways(0)
[[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0]]
>>> ways(1)
[[0, 1, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0]]
>>> ways(2)
[[3, 2, 2, 0, 0, 0, 0, 0],
[2, 2, 2, 0, 0, 0, 0, 0],
[2, 2, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0]]
>>> ways(3)
[[6, 11, 6, 4, 0, 0, 0, 0],
[11, 16, 9, 5, 0, 0, 0, 0],
[6, 9, 6, 3, 0, 0, 0, 0],
[4, 5, 3, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0]]
>>> ways(4)
[[38, 48, 45, 20, 9, 0, 0, 0],
[48, 64, 60, 28, 12, 0, 0, 0],
[45, 60, 51, 24, 9, 0, 0, 0],
[20, 28, 24, 12, 4, 0, 0, 0],
[9, 12, 9, 4, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0]]