算法 单源最短路径 dijkstra算法

有向带权图的单源最短路径经典算法是dijkstra,下面就对算法的过程和代码实现进行记录

 

算法过程:

1、数据结构:图的带权邻接矩阵G.Edge[u][i],如果u到i有边则G.Edge[u][i]等于<u,i>边的权值;否则G.Edge[u][i]等于∞。
一维数组dist[i]记录从起始点到i节点的最短路径长度,一维数组p[i]记录i节点最短路径的前驱
2、初始化:令集合S={u},其中u是起始点,对于V-S集合所有顶点i,初始化dist[i]=G.Edge[u][i],其中集合V是所有顶点的集合。如果i是u的邻接点,初始化p[i]=u,否则p[i]=-1
3、找最小:在集合V-S中按照贪心策略在dist中找出最小值dist[i],则顶点i就是离源点u最近的节点(注意:此处找到的最小i并不一定就是上一步找到节点的邻接点)
4、将找到的i节点加入到s集群,并更新V-S
5、判断是否结束:如果V-S为空则搜索结束,否则到步骤6
6、对结合V-S中与节点i邻接的顶点j,如果有dist[j]>dist[i]+G.Edge[i][j]则dist[j]=dist[i]+G.Edge[i][j];更新p[j]=i,继续执行步骤3

 

代码实现:

算法  单源最短路径 dijkstra算法
#!/usr/bin/env python
# -*- coding:utf-8 -*-


graphNodeList = [] #图存储节点信息
graphAdjMatrix = [] #有向权重图邻接矩阵
searchNodeInfo = [] #djstla最短距离已经遍历的节点
dist = [] #存储最短路径开销
p = [] #djstla最短路径每个顶点的直接前驱
MAX = 100000



#str切分后给列表赋值格式
def acquireNode():
    node_list = input("请输入途中所有的点,以空格分隔:")
    for nodeInfo in node_list.strip().split(" "):
        graphNodeList.append(nodeInfo)

#根据输入信息填写邻接矩阵
def acquireSideUndig():
    print("请输入图的所有边信息,格式为边的两个顶点,使用空格分隔。 eg:a b,如果全部信息输入完毕请输入end")
    while True:
        tempSide = input(">:")
        if tempSide.strip().lower() == "end":
            print("输入结束")
            break
        tempNodeList = tempSide.strip().split(" ")
        if len(tempNodeList) == 2:
            if tempNodeList[0] in graphNodeList and tempNodeList[1] in graphNodeList:
                createUndigraphAdjMatrix(tempNodeList[0], tempNodeList[1])
            else:
                print("边信息输入有误,请重新输入")
            continue
        else:
            print("输入有误请重新输入")
            continue

def acquireSideDig():
    print("请输入图的所有边信息,格式为边的两个顶点,使用空格分隔。 eg:a b,如果全部信息输入完毕请输入end")
    while True:
        tempSide = input(">:")
        if tempSide.strip().lower() == "end":
            print("输入结束")
            break
        tempNodeList = tempSide.strip().split(" ")
        if len(tempNodeList) == 2:
            if tempNodeList[0] in graphNodeList and tempNodeList[1] in graphNodeList:
                createDigraphAdjMatrix(tempNodeList[0], tempNodeList[1])
            else:
                print("边信息输入有误,请重新输入")
            continue
        else:
            print("输入有误请重新输入")
            continue

def acquireSideDigWeight():
    print("请输入图的所有边信息,格式为边的两个顶点和权重,使用空格分隔。 eg:a b weight,如果全部信息输入完毕请输入end")
    while True:
        tempSide = input(">:")
        if tempSide.strip().lower() == "end":
            print("输入结束")
            break
        tempNodeList = tempSide.strip().split(" ")
        if len(tempNodeList) == 3:
            if tempNodeList[0] in graphNodeList and tempNodeList[1] in graphNodeList:
                createDigraphAdjMatrixWeight(tempNodeList[0], tempNodeList[1], int(tempNodeList[2]))
            else:
                print("边信息输入有误,请重新输入")
            continue
        else:
            print("输入有误请重新输入")
            continue

#初始化邻接矩阵;注意多维数组初始化格式以及数据的浅拷贝坑
def initGraphAdjMatrixWeight(nodeNum):
    for row in range(nodeNum):
        tempList = []
        for column in range(nodeNum):
            tempList.append(MAX)
        graphAdjMatrix.append(tempList)

#根据输入顶点信息完成邻接表
def createUndigraphAdjMatrix(node0, node1):
    tempIndex1 = graphNodeList.index(node0)
    tempIndex2 = graphNodeList.index(node1)
    graphAdjMatrix[tempIndex1][tempIndex2] = 1
    graphAdjMatrix[tempIndex2][tempIndex1] = 1

def createDigraphAdjMatrix(node0, node1):
    tempIndex1 = graphNodeList.index(node0)
    tempIndex2 = graphNodeList.index(node1)
    graphAdjMatrix[tempIndex1][tempIndex2] = 1

def createDigraphAdjMatrixWeight(node0, node1, weight):
    tempIndex1 = graphNodeList.index(node0)
    tempIndex2 = graphNodeList.index(node1)
    graphAdjMatrix[tempIndex1][tempIndex2] = weight

#pRINT输出空格和换行的写法
def printAdjMatrix(nodeNum):
    for row in range(nodeNum):
        for column in range(nodeNum):
            print(graphAdjMatrix[row][column], end=" ")
        print("")

def maindigAdjMatWeight():
    acquireNode()
    initGraphAdjMatrixWeight(len(graphNodeList))
    acquireSideDigWeight()

def dijkstra(startnode):
    ##初始化
    for node in graphNodeList:
        # 初始化集合S,在集合S中的点在searchNodeInfo对应位置为True,默认初始化为False
        if node == startnode:
            searchNodeInfo.append(True)
        else:
            searchNodeInfo.append(False)
    for index, value in enumerate(graphAdjMatrix[graphNodeList.index(startnode)]):
        # 初始化前驱列表p;将startnode的邻接点前驱初始化为startnode,否则初始化为-1;初始化最短路径长度dist
        dist.append(value)
        if value < MAX:
            p.append(startnode)
        else:
            p.append(-1)
    ##将查找最小邻接点和使用最小邻接点更新dist p列表循环n-1次即可将所有数据更新完毕,起点已经是确定
    for loop in range(len(graphNodeList)-1):
        ##找dist中searchpath为False的最小值.
        tempdist = []
        for index, value in enumerate(searchNodeInfo):
            if value is False:
                tempdist.append(dist[index])
        #根据找到的最小值更新searchPath,判断节点是否查询完成;查询完成程序返回
        tempindex = dist.index(sorted(tempdist)[0])
        searchNodeInfo[tempindex] = True
        if False not in searchNodeInfo:
            printdijkstra(startnode)
            return 0
        #否则使用新加到search的节点更新其邻接点的dist值和p前驱
        for index, value in enumerate(graphAdjMatrix[tempindex]):
            if searchNodeInfo[index] is False and dist[index] > dist[tempindex] + value:
                dist[index] = dist[tempindex] + value
                p[index] = graphNodeList[tempindex]
    printdijkstra(startnode)
#输出原始节点到其它节点的最短路径长度和路径上的顶点
def printdijkstra(startnode):
    for i in range(len(graphNodeList)):
        if i == graphNodeList.index(startnode):
            print("这是起点自己%s" %startnode)
        else:
            print("起始点到顶点%s的距离是%d" %(graphNodeList[i], dist[i]),end="。")
            print("访问路径为:", end=" ")
            temppath = []
            temp_pi = i
            #找到顶点的所有前驱拼接起来即为最优路径
            while True:
                if p[temp_pi] != -1:
                    temppath.append(p[temp_pi])
                    temp_pi = graphNodeList.index(p[temp_pi])

                else:
                    break
            temppath.reverse()
            for path in temppath:
                print("%s->" % path, end="")
            print(graphNodeList[i])

if __name__ == "__main__":
    maindigAdjMatWeight()
    dijkstra(graphNodeList[0])
View Code

 

上一篇:P4779 【模板】单源最短路径(标准版)单源最短路Dijkstra


下一篇:被裁老程序员再就业计划之我可以用Dijkstra算法在回龙观送外卖