class Vertex:
def __init__(self,key):
self.id = key
self.connectedTo = {}
def addNeighbor(self,nbr,weight=0): # 加边 nbr是顶点对象的key
self.connectedTo[nbr] = weight
def __str__(self):
return str(self.id) + 'connectedTo: ' + str([x.id for x in self.connectedTo])
def getConnections(self):
return self.connectedTo.keys()
def getId(self):
return self.id
def getWeight(self,nbr):
return self.connectedTo[nbr]
class Graph: # 包含所有顶点的主表
def __init__(self):
self.vertList = {}
self.numVertices = 0
def addVertex(self,key): # 新加顶点
self.numVertices = self.numVertices + 1
newVertex = Vertex(key)
self.vertList[key] = newVertex
return newVertex
def getVertex(self,n): # 通过key查找顶点
if n in self.vertList:
return self.vertList[n]
else:
return None
def __contains__(self, n):
return n in self.vertList
def addEdge(self,f,t,cost=0):
if f not in self.vertList: # 看from节点和to节点是否存在
nv = self.addVertex(f) # 不存在的节点先添加
if t not in self.vertList:
nv = self.addVertex(t)
self.vertList[f].addNeighbor(self.vertList[t], cost) # 调用起始顶点的方法添加邻接边
def getVertices(self):
return self.vertList.keys()
def __iter__(self):
return iter(self.vertList.values())
词梯问题
def buildGraph(wordFile):
"""采用字典建立桶"""
d = {}
g = Graph()
wfile = open(wordFile, 'r')
for line in wfile:
word = line[:-1]
for i in range(len(word)):
bucket = word[:i] + '_' + word[i+1:] # 对每个单词设立桶 第一个字母空一下,第二个字母空一下...
if bucket in d: # 每个单词都会属于四个桶
d[bucket].append(word)
else:
d[bucket] = [word]
# 同一个桶单词之间建立边
for bucket in d.keys():
for word1 in d[bucket]:
for word2 in d[bucket]:
if word1 != word2: # 只要word1和word2不是同一个单词,就建立一条边放到图里
g.addEdge(word1, word2)
return g
所有节点都标注成了黑色,会有距离标注和回溯节点标注
def bfs(g,start):
start.setDistance(0)
start.setPred(None)
vertQueue = Queue()
vertQueue.enqueue(start)
while (vertQueue.size() > 0):
currentVert = vertQueue.dequeue() # 取队首作为当前顶点
for nbr in currentVert.getConnections(): # 遍历邻接顶点
if (nbr.getColor() == 'white'):
nbr.setColor('gray')
nbr.setDistance(currentVert.getDistance() + 1)
nbr.setPred(currentVert)
vertQueue.enqueue(nbr)
currentVert.setColor('black') # 当前顶点设黑色
def genlegalMoves(x,y,bdSize):
"""生成合法走棋位置"""
newMoves = []
# 马走日8个格子的偏移值
moveOffsets = [(-1,-2),(-1,2),(-2,-1),(-2,1),
(1,-2),(1,2),(2,-1),(2,1)]
for i in moveOffsets:
newX = x + i[0]
newY = y + i[1]
if legalCoord(newX,bdSize) and legalCoord(newY,bdSize):
newMoves.append(newX,newY)
return newMoves
def legalCoord(x,bdsize):
"""确认不会走出棋盘"""
if x >= 0 and x < bdsize:
return True
else:
return False
def knightGraph(bdSize):
"""构建走棋关系图"""
ktGraph = Graph()
for row in range(bdSize):
for col in range(bdSize): # 遍历每个格子
nodeId = posToNodeId(row,col,bdSize) # 每个格子都编上号
newPositions = genlegalMoves(row,col,bdSize) # 单步合法走棋
for e in newPositions: # 对每个位置进行判断
nid = posToNodeId(e[0],e[1],bdSize)
ktGraph.addEdge(nodeId,nid) # 添加边及顶点
return ktGraph
def posToNodeId(row,col,bdSize):
return row * bdSize + col
def knightTour(n,path,u,limit):
"""n:层次,即当前已经走了多少步 path:路径,即走过的格子加在path里面 u:当前顶点 limit:搜索总深度,在8x8中被设置为63"""
u.setColor('gray') # 当前节点设为灰色,表示正在探索
path.append(u) # 当前顶点加入路径
if n < limit:
nbrList = list(u.getConections()) # 对当前节点连接的所有合法移动逐一深入
i = 0
done = False
while i < len(nbrList) and not done:
if nbrList[i].getColor() == 'white': # 选择白色未经过的顶点深入
done = knightTour(n+1, path, nbrList[i], limit) # 层次加1,递归深入
i = i + 1
if not done: # 都无法完成总深度,回溯,试本层下一个顶点
path.pop()
u.setColor('white')
else:
done = True
return done
def orderByAvail(n):
"""修改了遍历下一格的次序
将u的合法移动目标棋盘格排序为:具有最少合法移动目标的格子优先搜索"""
resList = []
for v in n.getConnections():
if v.getColor() == 'white':
c = 0
for w in v.getConnections():
if w.getColor() == 'white':
c = c + 1
resList.append((c, v))
resList.sort(key=lambda x: x[0])
return [y[1] for y in resList]