图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法

Dijkstra算法解决了有向图G=(V,E)上带权的单源最短路径问题,但要求所有边的权值非负。

Dijkstra算法是贪婪算法的一个很好的例子。设置一顶点集合S,从源点s到集合中的顶点的最终最短路径的权值均已确定。算法反复选择具有最短路径估计的顶点u,并将u加入到S中,对u

的所有出边进行松弛。如果可以经过u来改进到顶点v的最短路径的话,就对顶点v的估计值进行更新。

如上图,u为源点,顶点全加入到优先队列中。

,队列中最小值为u(值为0),u出队列,对u的出边进行松弛(x、v、w),队列最小值为x。

将x出列加入S,将x的出边松弛(v、y、w),其中w的值需要更新(4<5),队列最小值为v。

将v出列,加入到S中,将v的出边松弛(w),因x已在S中,故不做松弛。队列中的最小值为y。

将y出列,y加入到S,松弛y的出边(w、z),更新w的值(3<4),队列最小值为w。

将w出列,加入到S中,松弛w的出边(z),队列最小值为z。

将z出列,加入到S中。将z的出边松弛(无),此时队列为空,算法结束。

Dijkstra算法的运行时间依赖于最小优先队列的具体实现。如果简单的运用数组实现求最小值,运行时间为O(V2+E)=O(V2)。

如果图比较稀疏,E=o(V2/lgV),如果用二叉最小堆实现,则为O((V+E)lgV)。

如果用斐波那契堆实现,可以提升到O(VlgV+E)。

import sys
class Vertex(object):
    def __init__(self,key):
        self.id=key
        self.adj={}
    def addNeighbor(self,nbr,weight=0):
        self.adj[nbr]=weight
    def getNeighbors(self):
        return self.adj.keys()
    def getId(self):
        return self.id
    def getWeight(self,key):
        return self.adj[key]
class Graph(object):
    def __init__(self):
        self.vertexlist={}
        self.size=0
    def addVertex(self,key):
        vertex=Vertex(key)
        self.vertexlist[key]=vertex
        self.size+=1
        return vertex
    def getVertex(self,key):
        return self.vertexlist.get(key)
    def __contains__(self,key):
        if key in self.vertexlist:
            return True
        else:
            return False
    def addEdge(self,f,t,weight=0):
        if f not in self.vertexlist:
            self.addVertex(f)
        if t not in self.vertexlist:
            self.addVertex(t)
        self.vertexlist[f].addNeighbor(self.vertexlist[t],weight)
    def getVertices(self):
        return self.vertexlist.keys()
    def __iter__(self):
        return iter(self.vertexlist.values())
def Dijkstra(G,s):
    path={}
    vertexlist=[]
    for v in G:
        vertexlist.append(v)
        path[v]=sys.maxsize
    path[s]=0
    queue=PriorityQueue(path)
    queue.buildHeap(vertexlist)
    while queue.size>0:
        vertex=queue.delMin()
        for v in vertex.getNeighbors():
            newpath=path[vertex]+vertex.getWeight(v)
            if newpath<path[v]:
                path[v]=newpath
                queue.perUp(v)
    return path
class PriorityQueue(object):
    def __init__(self,path):
        self.path=path
        self.queue=[]
        self.size=0
    def buildHeap(self,alist):
        self.queue=alist
        self.size=len(alist)
        for i in xrange(self.size/2-1,0,-1):
            self._perDown(i)
    def delMin(self):
        self.queue[0],self.queue[-1]=self.queue[-1],self.queue[0]
        minvertex=self.queue.pop()
        self.size-=1
        self._perDown(0)
        return minvertex

    def perUp(self,v):
        i=self.queue.index(v)
        self._perUp(i)
    def _perUp(self,i):
        if i>0:
            if self.path[self.queue[i]]<=self.path[self.queue[(i-1)/2]]:
                self.queue[i],self.queue[(i-1)/2]=self.queue[(i-1)/2],self.queue[i]
                self._perUp((i-1)/2)
    def _perDown(self,i):
        left=2*i+1
        right=2*i+2
        little=i
        if left<=self.size-1 and self.path[self.queue[left]]<=self.path[self.queue[i]]:
            little=left
        if right<=self.size-1 and self.path[self.queue[right]]<=self.path[self.queue[little]]:
            little=right
        if little!=i:
            self.queue[i],self.queue[little]=self.queue[little],self.queue[i]
            self._perDown(little)

if __name__==‘__main__‘:
    g= Graph()
    g.addEdge(‘u‘,‘x‘,1)
    g.addEdge(‘u‘,‘v‘,2)
    g.addEdge(‘u‘,‘w‘,5)
    g.addEdge(‘x‘,‘v‘,2)
    g.addEdge(‘x‘,‘y‘,1)
    g.addEdge(‘x‘,‘w‘,3)
    g.addEdge(‘v‘,‘w‘,3)
    g.addEdge(‘y‘,‘w‘,1)
    g.addEdge(‘y‘,‘z‘,1)
    g.addEdge(‘w‘,‘z‘,5)
    u=g.getVertex(‘u‘)
    path=Dijkstra(g,u)
    for v in path:
        print v.id,path[v]

  

图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法

时间: 2024-11-10 13:16:22

图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法的相关文章

图的单源最短路径:Dijkstra算法实现

本文介绍的是图的非负权值的单源最短路径问题.问题的提出是,对于有权图D,t提供源点v,要找到从v到其他所有点的最短路径,即单源最短路径问题,在本文中,解决这一问题,是普遍比较熟悉的Dijkstra算法. 算法核心思想参见维基.简而言之,设集合S存放已经求出了最短路径的点.初始状态S中只有一个点v0,之后每求得v0到vn的最短路径,就会更新v0到所有vn邻接的点的一致的最短路径(不一定是最终的最短路径),如此重复,每次会确定v0到一个点的最短路径,确定好的点加入S中,直至所有点进入S结束.在本文中

带负权图的单源最短路径算法:Bellman-Ford算法

算法简介 前面介绍过图的单源最短路径算法Dijkstra算法,然而Dijkstra算法无法判断含负权边的图的最短路.如果遇到负权,在没有负权回路存在时(负权回路的含义是,回路的权值和为负.)即便有负权的边,也可以采用Bellman-Ford算法正确求出最短路径. Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数 w是 边集 E 的映射.对图G运行Bellman-Ford算法的结果是一个布尔值,表

单源最短路径(dijkstra算法)php实现

做一个医学项目,其中在病例评分时会用到单源最短路径的算法.单源最短路径的dijkstra算法的思路如下: 如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点.那么(Vi...Vk)也必定是从i到k的最短路径.Dijkstra是以最短路径长度递增,逐次生成最短路径的算法.例如:对于源顶点V0,首先选择其直接相邻的顶点中长度最短的顶点Vi,那么当前已知可得从V0到达Vj顶点的最短距离dist[j]=min{dist[j],dist[i]+cost[i][j]}.假设G

单源最短路径问题-Dijkstra算法

同样是层序遍历,在每次迭代中挑出最小的设置为已知,收敛 表初始化 void InitTable(Vertex Start, Graph G, Table T) { int i; ReadGraph(G, T); for (i=0; i<NumVertex; i++) { T[i].Known = False; T[i].Dist = Infinity; T[i].Path = NotAVertex; } T[Start].dist = 0; } 显示实际路径 void PrintPath(Ver

单源最短路径(Dijkstra)——贪心算法

Dijkstra算法是解单源最短路径问题的贪心算法.其基本思想是,设置顶点集合点集合S并不断地做贪心选择来扩充这个集合.一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知.初始时,S中仅含有源.设u是G的其一顶点.把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组Distance记录当前每个顶点所对应的最短特殊路径长度.Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶占,Distance就记录了从源到所有其它顶点之间最短路径长度. 例如下图中的有向图,应用Dij

单源最短路径_贪心算法

问题描述 给定带权有向图G =(V,E),其中每条边的权是非负实数.另外,还给定V中的一个顶点,称为源.现在要计算从源到所有其它各顶点的最短路长度.这里路的长度是指路上各边权之和. 策略与数据结构 其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合.一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知. 相关解释 观测域:假设起点为v点,观测域便为v点的四周,即v的所有邻接点: 点集 V:图中所有点的集合: 点集 S:已经找到最短路径的终点集合: 数组 D:存储观测域内能观测到的最

单源点最短路径的Dijkstra算法

在带权图(网)里,点A到点B所有路径中边的权值之和为最短的那一条路径,称为A,B两点之间的最短路径;并称路径上的第一个顶点为源点(Source),最后一个顶点为终点(Destination).在无权图中,最短路径则是两点之间经历的边数最少的路径.实际上,只要把无权图上的每条边都看成是权值为1的边,那么无权图和带权图的最短路径是一致的. 给定一个带权有向图G=(V,E),指定图G中的某一个顶点的V为源点,求出从V到其他各顶点之间的最短路径,这个问题称为单源点最短路径问题. 迪杰斯特拉(Dijkst

[模板]单源最短路径(Dijkstra)

如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 主要还是再打一遍最短路,这种算法我用的不多... 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 inline int read() 5 { int x=0;bool f=0;char ch=getchar(); 6 while(!isdigit(ch)){ f=(ch==45);ch=getchar();} 7 while(is

单源最短路Dijkstra算法——matlab实现

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算). 此外,引进两个集合S和U.S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离). 初始时,S中只有起点s:U中是除s之外的顶点,并且U中顶点的路径是"起点s