蓝桥杯(跳马)

回溯算法(跳马问题)

跳马

资源限制
时间限制: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]]

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值