【数据结构】【图及算法】词梯问题,广度优先搜索,骑士周游问题

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]

 

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值