本题是要找最长路径,应该广度优先搜索和深度优先搜索都可以。本文先考虑深度优先搜索。
本题与以前的类似的题目的区别在于约束条件的不同,比如说之前有类似的题目的约束条件是不能重复通过一条边,或者路线不能交叉,等等。本题的约束条件是在同一条直线上不能移动两次。因此在深度优先搜索过程中需要记录当前搜索路径中每条直线上已经移动过的次数,并结合边界条件下来确定从当前位置出发的下一步可能的移动方向。
移动网格如上图所示,以n和m分别表示纵向宽度和横向长度,出发点坐标为(0,0),目标点坐标为(n,m)。横向和纵向分别有(n+1)条直线和(m+1) 条直线,分别用H和V表示(n+1)条横线和(m+1)条纵线已经移动过的次数。
深度优先搜索算法流程如下:
最后,将curpos初始化为(0,0),steps初始化0,H和V分别初始化为适当size的全零数组,然后调用dfs()到最终退出后所得到的maxsteps即为所求结果。在以下代码实现中,maxsteps指定为全局变量,这样避免了参数传递的麻烦。
以上流程中,“还原H和V” 比较容易忘记,这个相当于函数递归调用退回时的退栈处理。只不过递归调用的退栈处理是编译器进行了自动管理。但是如果像steps那样的传递的话,由于没有更新当前递归层次的值,所以就不需要还原处理。
# -*- coding: utf-8 -*-
"""
Created on Sat Oct 9 07:12:37 2021
@author: chenxy
"""
# import sys
import time
from collections import deque
n = 5
m = 6
target = (n,m)
maxsteps = 0
H = (n+1)*[0]
V = (m+1)*[0]
def dfs(curpos, H, V, steps):
# print(curpos, H, V, steps)
global maxsteps
if curpos == target:
if maxsteps < steps:
maxsteps = steps
# Up trial
if curpos[0] > 0 and V[curpos[1]] < 2:
nxtpos = (curpos[0]-1, curpos[1])
V[curpos[1]] = V[curpos[1]] + 1
dfs(nxtpos, H, V, steps+1)
V[curpos[1]] = V[curpos[1]] - 1
# Down trial
if curpos[0] < n and V[curpos[1]] < 2:
nxtpos = (curpos[0]+1, curpos[1])
V[curpos[1]] = V[curpos[1]] + 1
dfs(nxtpos, H, V, steps+1)
V[curpos[1]] = V[curpos[1]] - 1
# Left trial
if curpos[1] > 0 and H[curpos[0]] < 2:
nxtpos = (curpos[0], curpos[1]-1)
H[curpos[0]] = H[curpos[0]] + 1
dfs(nxtpos, H, V, steps+1)
H[curpos[0]] = H[curpos[0]] - 1
# Right trial
if curpos[1] < m and H[curpos[0]] < 2:
nxtpos = (curpos[0], curpos[1]+1)
H[curpos[0]] = H[curpos[0]] + 1
dfs(nxtpos, H, V, steps+1)
H[curpos[0]] = H[curpos[0]] - 1
return
tStart = time.perf_counter()
dfs((0,0),H,V,0)
tCost = time.perf_counter() - tStart
print('n={0}, m={1}, maxsteps={2}, tCost = {3:6.3f}(sec)'.format(n,m,maxsteps,tCost))
运行结果:n=5, m=6, maxsteps=25, tCost = 1.682(sec)
运行速度有点差强人意。
接下来看看用广度优先搜索策略是不是能够更快一些。