回溯算法(跳马问题)
跳马
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
一个8×8的棋盘上有一个马初始位置为(a,b),他想跳到(c,d),问是否可以?如果可以,最少要跳几步?
输入格式
一行四个数字a,b,c,d。
输出格式
如果跳不到,输出-1;否则输出最少跳到的步数。
样例输入
1 1 2 3,
样例输出
1
数据规模和约定
0<a,b,c,d≤8且都是整数。
马走日,在棋盘上,马从任意一个点出发可以到达棋盘上所有的点。该题要求输出最少跳到的步数,即最短路径,可以用回溯法,搜索每一条路经,并记录到达终点所需的步数,不断更新最小步数。
1、对于棋盘上的任意一个点,马可以走的路径有p=[[1,2],[2,1],[-1,2],[-1,-2],[1,-2],[-2,1],[-2,-1],[2,-1]]。
2、用一个二维数组v标记棋盘上的每一个点是否已经走过。因为可以走的路径里面有负数,有些节点会重复走到,会形成死循环。所以当遇到重复走的点时要跳过。
3、如果走的步数已经大于最小步数,即step>=minstep,则返回,换一条路径继续搜索。
4、当马走到终点时,说明走到终点之前的步数一直小于最小步数,此时可以更新minstep(最小需要跳的步数),接着返回继续搜索,不断更新minstep,直到找到到达终点所需的最小步数。
代码如下:
# 跳马问题
a,b,c,d=map(int,input().split())
p=[[1,2],[2,1],[-1,2],[-1,-2],[1,-2],[-2,1],[-2,-1],[2,-1]]#每一步可以走的路径
minstep=float('inf')#初始化最小步数
v=[[0 for i in range(9)]for j in range(9)]#用二维数组记录棋盘上的点是否已经走过
def huisu(x,y,step):
global minstep
if step>=minstep:#如果走的步数已经大于最小步数,则返回,换一条路径继续搜索
return
if x==c and y==d:#到达终点,更新最小步数
minstep=step
return
for i in range(8):
nx=x+p[i][0]
ny=y+p[i][1]#下一步走到的点
if nx >= 1 and nx <= 8 and ny >= 1 and ny <= 8:
if v[nx][ny]==1:#可以走的路径有[-2,-1],有负数,因此有些节点可能会重复走到,会无限循环,要跳过这些重复的点
continue
v[nx][ny]=1
huisu(nx,ny,step+1)
v[nx][ny]=0
x=nx-p[i][0]
y=ny-p[i][1]#回溯,撤销处理结果
huisu(a,b,0)
print(minstep)
测试结果:
1 1 8 8
6
###如果想要输出最短路径,可以用path来存从起点到达终点的单条路经,用res来存从起点到达终点的多条路径,代码如下:
# 跳马问题
a,b,c,d=map(int,input().split())
p=[[1,2],[2,1],[-1,2],[-1,-2],[1,-2],[-2,1],[-2,-1],[2,-1]]#每一步可以走的路径
minstep=float('inf')#初始化最短路径
v=[[0 for i in range(9)]for j in range(9)]#用二维数组记录棋盘上的点是否已经走过
path=[[a,b]]#存放马走到终点的单条路经
res=[]#存放马走到终点的多条路径
def huisu(x,y,step):
global minstep
if step>=minstep:#如果走的步数已经大于最小步数,则返回,换一条路径继续搜索
return
if x==c and y==d:#到达终点,更新最小步数
minstep=step
res.append(path.copy())
return
for i in range(8):
nx=x+p[i][0]
ny=y+p[i][1]#下一步走到的点
if nx >= 1 and nx <= 8 and ny >= 1 and ny <= 8:
if v[nx][ny]==1:#可以走的路径有[-2,-1],有负数,因此有些节点可能会重复走到,会无限循环,要跳过这些重复的点
continue
v[nx][ny]=1
path.append([nx,ny])
huisu(nx,ny,step+1)
path.pop()
v[nx][ny]=0
x=nx-p[i][0]
y=ny-p[i][1]#回溯,撤销处理结果
huisu(a,b,0)
print(minstep)
# print(res)
# 输出最短路径
for r in res:
if len(r)-1==minstep:
print(r)
测试结果:
1 1 8 8
6
[[1, 1], [2, 3], [3, 5], [4, 7], [6, 8], [7, 6], [8, 8]]