解决骑士周游问题来学习深度优先搜索
棋盘格上每个合理走法都代表一条边,由此建立图。
算法:
初始化一个图
对每一格进行循环
计算每一格可以连接的其他格子
为它们添加边
返回图
knghtTour()这个递归函数的代码看了挺久的才看懂…
感觉对于递归还是理解地不够深入。
def knightTour(n, path, u, limit):
# 访问过u
u.setColor('gray')
path.append(u)
# 要递归的情况
if n < limit:
nbr_list = list(u.getConnections())
i = 0
done = False
while i < len(nbr_list) and not done:
if nbr_list[i].getColor() == 'white':
# 递归
done = knightTour(n + 1, path, nbr_list[i], limit)
i += 1
# 如果当前节点没有白色的邻接节点,就不会执行上面的递归。
# 但是此时n < limit,整张图中一定还是有白色节点的,我们遇到了死路,需要回溯
if not done:
path.pop()
u.setColor('white')
# base case:n == limit
else:
done = True
return done
理解:
跟着书上的一下例子走一遍,会理解的好一些:

骑士周游是复杂度O(k^N)的算法,N是棋盘上的格子数。
启发式技术Warnsdorff 算法:
就是记录了当前节点的相邻顶点们的可移动格子数,然后将可移动格子数少的相邻点排在前面。这样探索的次数会少一点。

代码:
def orderedByAvail(n):
"""获取邻接点可以到达的格子数"""
resList = []
for v in n.getConnections():
c = 0
for w in v.getConnections():
if w.getColor() == 'white':
c += 1
resList.append((c, v))
# 可访问格子数少的点排前面
resList = sorted(resList, key=lambda x: x[0])
return [y[1] for y in resList]
几个需要注意的点:

代码:
class DFSGraph(Graph):
def __init__(self):
super().__init__()
self.time = 0
def dfs(self):
"""对图中的每一个顶点dfsvisit,而不是从任意一个起始点开始搜索,是为了保证所有顶点都被搜索过"""
for vertex in self:
vertex.setColor('white') # 先将图中每个点颜色初始化为白
vertex.setPred(-1) # pred初始化为-1
for avertex in self:
if avertex.geteColor() == 'white':
self.dfsvisit(avertex)
def dfsvisit(self, start_vertex):
self.time += 1 # 每碰到一个点一次,次数+1
start_vertex.setDiscovery(self.time) # 设置第一次访问该点的时间
"""深度优先搜索"""
start_vertex.setColor('gray') # 正在访问此顶点
for v in start_vertex.getConnections():
if v.getColor() == 'white':
self.dfsvisit(v)
# 深度搜素完,返回到初始点,将初始点设置为黑。
start_vertex.setColor('black')
self.time += 1 # 此时+1是因为递归返回
start_vertex.setFinish(self.time) # 设置返回到该点时所用的时间