最短路径算法 订阅
从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径。解决最短路的问题有以下算法,Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法等。 展开全文
从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径。解决最短路的问题有以下算法,Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法等。
信息
解决问题
最短路径问题
属    于
图论
定    义
各边上权值之和最小的一条路径
中文名
最短路径算法
外文名
Shortest Path Algorithm
包    括
Dijkstra算法、Floyd算法等
最短路径算法定义
最短路径问题是图论研究中的一个经典算法问题,旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。算法具体的形式包括:(1)确定起点的最短路径问题- 即已知起始结点,求最短路径的问题。适合使用Dijkstra算法。(2)确定终点的最短路径问题- 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。(3)确定起点终点的最短路径问题- 即已知起点和终点,求两结点之间的最短路径。(4)全局最短路径问题- 求图中所有的最短路径。适合使用Floyd-Warshall算法 [1]  。
收起全文
精华内容
下载资源
问答
  • 最短路径算法最短路径算法最短路径算法最短路径算法
  • 课题结题论文 题 目 最短路径算法分类与应用研究 学 院 专 业 班 级 学生姓名 指导教师 2008年10月 最短路径算法分类与应用研究 姓 名 班 级 指导教师 摘要 本文研究目的在丁收集整理关丁最短路径的普遍算法 为研究...
  • 最短路径算法

    2017-11-30 16:49:21
    BruteForce遍历所有可能得路径求得最短路径算法,导入可用,java实现,有注释,原创代码
  • 而最小费用流的最短路径算法,则是从0流开始,往最短路径上分配流量,直到流量达到v0为止。 最小费用流的最短路径算法图例 容量-费用网络,初始分配0流: 找出残余容量网络上的最短路径:s->2->t(距离为4)...

    屈婉玲《算法设计与分析》第2版第7章网络流算法学习笔记。

    概述

    最小费用流的负回路算法,是先任意分配流量v0,再将流量调整到权值较小的边上,参考:

    基于Floyd算法的最小费用流的负回路算法(图解)

    而最小费用流的最短路径算法,则是从0流开始,往最短路径上分配流量,直到流量达到v0为止。

    最小费用流的最短路径算法图例

    容量-费用网络,初始分配0流:
    在这里插入图片描述
    找出残余容量网络上的最短路径:s->2->t(距离为4),分配5个单位流量,得到f1:
    在这里插入图片描述
    更新残余网络找出最短路径:s->1->2->t (距离为5),分配1个单位流量,得到f2:
    在这里插入图片描述
    更新残余网络找出最短路径:s->1->t (距离为6),分配2个单位流量(v0-f2=2),得到f3:
    在这里插入图片描述
    至此流量达到v0,f3即为所求。

    伪代码

    1. f ← 0
    2. 构造N(f)
    3. 调用Floyd算法计算N(f)中s-t最短路径
    4. if N(f)无s-t路径 then return “无流量v0的可行流”  //f是最大流,且v(f)<v0
    5.N(f)的s-t增广路径中找出最短路径
    6. 为最短路径尽可能分配流量,且不超过v0,f ← f1
    7. if v(f)<v0 then goto 2 
    8. return f
    

    Ford算法

    上面算法中找最短路径时,使用L.R.Ford 提出的 Ford 算法替代Floyd算法更好,因为只需求单源最短路径。Ford算法可以求无负回路的赋权有向图中单源最短路径(和Dijkstra条件和功能一样)。

    设赋权有向图D=<V, E, w> 无负回路,n=|V|。

    使用动态规划法,记d(k)(i)为D中v1到vi边数不超过k的最短路径的权(2<=i<=n, k>=1),可得递推公式:

    d(0)(1) = 0;  d(0)(i) = +∞, 2<=i<=n
    d(k)(i) = min{d(k-1)(i), d(k-1)(j) + w(j, i)} | <vj, vi>∈E }, 1<=i<=n, k>=1
    

    因为图中无负回路,所以最短路径包含边数<=n-1,所以d(n-1)(i)即为所求。

    为了保存详细路径信息,用h(k)(i)保存i的下一跳,递推公式为:

    h(0)(1) = 1; h(0)(i) = 0, 2<=i<=n
    h(k)(i) = h(k-1)(i), 若d(k-1)(i) <= d(k-1)(j) + w(j, i)
    	      min{j},         若d(k-1)(i) > d(k-1)(j) + w(j, i)
    

    Ford单源最短路径算法图例

    在这里插入图片描述
    由d(4)和h(4)可知:

    v1到v2最短路径长为1, 1->2
    v1到v3最短路径长为1, 1->2->5->3
    v1到v4最短路径长为1, 1->4
    v1到v5最短路径长为1, 1->2->5  
    

    伪代码

    //初始化,k=0
    d(1)1=0h(1)1
    for i←2 to n do
    	d(i)+, h(i)0
    for k←1 to n-1 do
    	for i←1 to n do
    		for <vj, vi>∈E do
    			if d(j)+w(j,i) < d(i) then
    				d(i)d(k-1)(j)+w(j,i)
    				h(i) ← j
    //若n-1次循环后还能更新d(i),说明到该点的最短路径还未找到,那么必定是存在负回路,返回FALSE
    for i←1 to n do
    	for <vj, vi>∈E do
    		if d(j)+w(j,i) < d(i) then
    			return false
    return d, h
    

    算法对比

    对比Floyd算法

    Ford算法复杂度和Floyd算法一样为O(n^3),但Ford算法只保留单源最短路径,Floyd计算并保存多源最短路径,所以比Floyd算法节省空间,效率也较高。

    在找s-t最短路径时Ford算法比Floyd算法更适合。

    对比Dijkstra算法

    Ford算法复杂度也可表示为O(n * m),m = |E|;相比之下,Dijkstra算法复杂度为O(n^2);当图是稀疏图时,二者相差不大。

    Dijkstra算法不能处理有负回路的图,而Ford算法能

    展开全文
  • FORD最短路径算法

    2018-09-16 07:20:08
    FORD最短路径算法,非常适合奥赛培训所用课件。最短路径算法适合基础学习者。
  • 主要介绍了java实现最短路径算法之Dijkstra算法, Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法,有兴趣的可以了解一下
  • 单源最短路径算法Dijkstra算法解决的问题算法的思想Java代码实现 算法解决的问题 在图中寻找从一个点到其他点的最短路径问题,例如,外卖小哥从店里出发,到其他各个买家的最短路径是多少 算法的思想 该算法使用贪心...

    算法解决的问题

    在图中寻找从一个点到其他点的最短路径问题,例如,外卖小哥从店里出发,到其他各个买家的最短路径是多少

    算法的思想

    该算法使用贪心的思想,具有两个阈,一个是S阈(表示已经加入的点,初始只有起点),一个是U阈,表示还没有加入的。
    首先有个dis数组,记录的是从起点到达其他点的最短路径,然后选择最短的那个,加入到S中去。然后由于新点的加入,更新dis数组,直到所有的点都加入S中为止。

    Java代码实现

    private static void dijkstra(int[][] graph, int[] dis, boolean[] visited) {
            while (true){
                int min = Integer.MAX_VALUE;
                int index=-1;
                for(int i=0;i<dis.length;i++){
                    if(visited[i]){
                        continue;
                    }else{
                        if(min>dis[i]) {
                            min = Math.min(min, dis[i]);
                            index = i;
                        }
                    }
                }
                if(index==-1){//说明所有的点都加入S中,结束
                    break;
                }
                visited[index]=true;//加入到S中
                for(int i=0;i<graph[0].length;i++){//更新dis
                    if(graph[index][i]!=Integer.MAX_VALUE){
                        dis[i]=Math.min(dis[i],min+graph[index][i]);
                    }
                }
            }
        }
    
    展开全文
  • 最短路径算法在日常生活中,我们如果需要常常往返A地区和B地区之间,我们最希望知道的可能是从A地区到B地区间的众多路径中,那一条路径的路途最短。最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由...

    1最短路径算法

    在日常生活中,我们如果需要常常往返A地区和B地区之间,我们最希望知道的可能是从A地区到B地区间的众多路径中,那一条路径的路途最短。最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。 算法具体的形式包括:

    (1)确定起点的最短路径问题:即已知起始结点,求最短路径的问题。

    (2)确定终点的最短路径问题:与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。

    (3)确定起点终点的最短路径问题:即已知起点和终点,求两结点之间的最短路径。

    (4)全局最短路径问题:求图中所有的最短路径。

    用于解决最短路径问题的算法被称做“最短路径算法”, 有时被简称作“路径算法”。 最常用的路径算法有:Dijkstra算法、A*算法、Bellman-Ford算法、Floyd-Warshall算法、Johnson算法。

    本文主要研究Dijkstra算法的单源算法。

    Dijkstra算法是典型最短路算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。

    Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。

    Dijkstra算法思想为:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将 加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

    (1)初始时,S只包含源点,即S=,v的距离为0。U包含除v外的其他顶点,U中顶点u距离为边上的权(若v与u有边)或 )(若u不是v的出边邻接点)。

    (2)从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。

    (3)以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u(u U)的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。

    (4)重复步骤(2)和(3)直到所有顶点都包含在S中。

    如下图,设A为源点,求A到其他各顶点(B、C、D、E、F)的最短路径。线上所标注为相邻线段之间的距离,即权值。(注:此图为随意所画,其相邻顶点间的距离与图中的目视长度不能一一对等)

    图一:Dijkstra无向图

    算法执行步骤如下表:【注:图片要是看不到请到“相册--日志相册”中,名为“Dijkstra算法过程”的图就是了】

    [1]黄国瑜、叶乃菁,数据结构,清华大学出版社,2001年8月第1版

    [3]李春葆,数据结构教程,清华大学出版社,2005年1月第1版

    [3]Dijkstra算法,http://baike.baidu.com/view/7839.htm

    展开全文
  • 图的四种最短路径算法

    万次阅读 多人点赞 2017-12-27 12:03:57
    本文总结了图的几种最短路径算法的实现:深度或广度优先搜索算法,弗洛伊德算法,迪杰斯特拉算法,Bellman-Ford算法1),深度或广度优先搜索算法(解决单源最短路径)从起始结点开始访问所有的深度遍历路径或广度...

    本文总结了图的几种最短路径算法的实现:深度或广度优先搜索算法,弗洛伊德算法,迪杰斯特拉算法,Bellman-Ford算法


    1),深度或广度优先搜索算法(解决单源最短路径)
    从起始结点开始访问所有的深度遍历路径或广度优先路径,则到达终点结点的路径有多条,取其中路径权值最短的一条则为最短路径。

    下面是核心代码:

    1. void dfs(int cur, int dst){    
    2.     /***operation***/    
    3.     
    4.     /***operation***/    
    5.     if(minPath < dst) return;//当前走过路径大于之前最短路径,没必要再走下去    
    6.     if(cur == n){//临界条件    
    7.         if(minPath > dst) minPath = dst;    
    8.         return;    
    9.     }    
    10.     else{    
    11.         int i;    
    12.         for(i = 1; i <= n; i++){    
    13.             if(edge[cur][i] != inf && edge[cur][i] != 0 && mark[i] == 0){    
    14.                 mark[i] = 1;    
    15.                 dfs(i, dst+edge[cur][i]);    
    16.                 mark[i] = 0;  //需要在深度遍历返回时将访问标志置0              
    17.             }    
    18.         }    
    19.         return;    
    20.     }    
    21. }    
    例1:下面是城市的地图,注意是单向图,求城市1到城市5的最短距离。(引用的是上次总结的图论(一)中1)的例2)

    1. /***先输入n个结点,m条边,之后输入有向图的m条边,边的前两元素表示起始结点,第三个值表权值,输出1号城市到n号城市的最短距离***/    
    2. /***算法的思路是访问所有的深度遍历路径,需要在深度遍历返回时将访问标志置0***/    
    3. #include <iostream>    
    4. #include <iomanip>    
    5. #define nmax 110    
    6. #define inf 999999999    
    7. using namespace std;    
    8. int n, m, minPath, edge[nmax][nmax], mark[nmax];//结点数,边数,最小路径,邻接矩阵,结点访问标记    
    9. void dfs(int cur, int dst){    
    10.     /***operation***/    
    11.     
    12.     /***operation***/    
    13.     if(minPath < dst) return;//当前走过路径大于之前最短路径,没必要再走下去    
    14.     if(cur == n){//临界条件    
    15.         if(minPath > dst) minPath = dst;    
    16.         return;    
    17.     }    
    18.     else{    
    19.         int i;    
    20.         for(i = 1; i <= n; i++){    
    21.             if(edge[cur][i] != inf && edge[cur][i] != 0 && mark[i] == 0){    
    22.                 mark[i] = 1;    
    23.                 dfs(i, dst+edge[cur][i]);    
    24.                 mark[i] = 0;                
    25.             }    
    26.         }    
    27.         return;    
    28.     }    
    29. }    
    30.     
    31. int main(){    
    32.     while(cin >> n >> m && n != 0){    
    33.         //初始化邻接矩阵    
    34.         int i, j;    
    35.         for(i = 1; i <= n; i++){    
    36.             for(j = 1; j <= n; j++){    
    37.                 edge[i][j] = inf;    
    38.             }    
    39.             edge[i][i] = 0;    
    40.         }    
    41.         int a, b;    
    42.         while(m--){    
    43.             cin >> a >> b;    
    44.             cin >> edge[a][b];    
    45.         }    
    46.         //以dnf(1)为起点开始递归遍历    
    47.         memset(mark, 0, sizeof(mark));    
    48.         minPath = inf;    
    49.         mark[1] = 1;    
    50.         dfs(1, 0);    
    51.         cout << minPath << endl;    
    52.     }    
    53.     return 0;    
    54. }    
    程序运行结果如下:



    2),弗洛伊德算法(解决多源最短路径):时间复杂度O(n^3),空间复杂度O(n^2)
    基本思想:最开始只允许经过1号顶点进行中转,接下来只允许经过1号和2号顶点进行中转......允许经过1~n号所有顶点进行中转,来不断动态更新任意两点之间的最短路程。即求从i号顶点到j号顶点只经过前k号点的最短路程。

    分析如下:1,首先构建邻接矩阵Floyd[n+1][n+1],假如现在只允许经过1号结点,求任意两点间的最短路程,很显然Floyd[i][j] = min{Floyd[i][j], Floyd[i][1]+Floyd[1][j]},代码如下:

    1. for(i = 1; i <= n; i++){  
    2.     for(j = 1; j <= n; j++){  
    3.         if(Floyd[i][j] > Floyd[i][1] + Floyd[1][j])  
    4.             Floyd[i][j] = Floyd[i][1] + Floyd[1][j];  
    5.     }  
    6. }  
    2,接下来继续求在只允许经过1和2号两个顶点的情况下任意两点之间的最短距离,在已经实现了从i号顶点到j号顶点只经过前1号点的最短路程的前提下,现在再插入第2号结点,来看看能不能更新更短路径,故只需在步骤1求得的Floyd[n+1][n+1]基础上,进行Floyd[i][j] = min{Floyd[i][j], Floyd[i][2]+Floyd[2][j]};......
    3,很显然,需要n次这样的更新,表示依次插入了1号,2号......n号结点,最后求得的Floyd[n+1][n+1]是从i号顶点到j号顶点只经过前n号点的最短路程。故核心代码如下:

    1. #define inf 99999999  
    2. for(k = 1; k <= n; k++){  
    3.     for(i = 1; i <= n; i++){  
    4.         for(j = 1; j <= n; j++){  
    5.             if(Floyd[i][k] < inf && Floyd[k][j] < inf && Floyd[i][j] > Floyd[i][k] + Floyd[k][j])  
    6.                 Floyd[i][j] = Floyd[i][k] + Floyd[k][j];  
    7.         }  
    8.     }  
    9. }  
    例1:寻找最短的从商店到赛场的路线。其中商店在1号结点处,赛场在n号结点处,1~n结点中有m条线路双向连接。

    1. /***先输入n,m,再输入m个三元组,n为路口数,m表示有几条路其中1为商店,n为赛场,三元组分别表起点,终点,该路径长,输出1到n的最短路径***/  
    2. #include <iostream>  
    3. using namespace std;  
    4. #define inf 99999999  
    5. #define nmax 110  
    6. int edge[nmax][nmax], n, m;  
    7. int main(){  
    8.     while(cin >> n >> m && n!= 0){  
    9.         //构建邻接矩阵  
    10.         int i, j;  
    11.         for(i = 1; i <= n; i++){  
    12.             for(j = 1; j <= n; j++){  
    13.                 edge[i][j] = inf;  
    14.             }  
    15.             edge[i][i] = 0;  
    16.         }  
    17.         while(m--){  
    18.             cin >> i >> j;  
    19.             cin >> edge[i][j];  
    20.             edge[j][i] = edge[i][j];  
    21.         }  
    22.         //使用弗洛伊德算法  
    23.         int k;  
    24.         for(k = 1; k <= n; k++){  
    25.             for(i = 1; i <= n; i++){  
    26.                 for(j = 1; j <= n; j++){  
    27.                     if(edge[i][k] < inf && edge[k][j] < inf && edge[i][j] > edge[i][k] + edge[k][j])  
    28.                         edge[i][j] = edge[i][k] + edge[k][j];  
    29.                 }  
    30.             }  
    31.         }  
    32.         cout << edge[1][n] << endl;  
    33.     }  
    34.     return 0;  
    35. }  
    程序运行结果如下:



    3),迪杰斯特拉算法(解决单源最短路径)
    基本思想:每次找到离源点(如1号结点)最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。
    基本步骤:1,设置标记数组book[]:将所有的顶点分为两部分,已知最短路径的顶点集合P和未知最短路径的顶点集合Q,很显然最开始集合P只有源点一个顶点。book[i]为1表示在集合P中;
    2,设置最短路径数组dst[]并不断更新:初始状态下,令dst[i] = edge[s][i](s为源点,edge为邻接矩阵),很显然此时dst[s]=0,book[s]=1。此时,在集合Q中可选择一个离源点s最近的顶点u加入到P中。并依据以u为新的中心点,对每一条边进行松弛操作(松弛是指由结点s-->j的途中可以经过点u,并令dst[j]=min{dst[j], dst[u]+edge[u][j]}),并令book[u]=1;
    3,在集合Q中再次选择一个离源点s最近的顶点v加入到P中。并依据v为新的中心点,对每一条边进行松弛操作(即dst[j]=min{dst[j], dst[v]+edge[v][j]}),并令book[v]=1;
    4,重复3,直至集合Q为空。
    以下是图示:


    核心代码如下所示:

    1. #define inf 99999999  
    2. /***构建邻接矩阵edge[][],且1为源点***/  
    3. for(i = 1; i <= n; i++) dst[i] = edge[1][s];  
    4. for(i = 1; i <= n; i++) book[i] = 0;  
    5. book[1] = 1;  
    6. for(i = 1; i <= n-1; i++){  
    7.     //找到离源点最近的顶点u,称它为新中心点  
    8.     min = inf;  
    9.     for(j = 1; j <= n; j++){  
    10.         if(book[j] == 0 && dst[j] < min){  
    11.             min = dst[j];  
    12.             u = j;  
    13.         }  
    14.     }  
    15.     book[u] = 1;  
    16.     //更新最短路径数组  
    17.     for(k = 1; k <= n; k++){  
    18.         if(edge[u][k] < inf && book[k] == 0){  
    19.             if(dst[k] > dst[u] + edge[u][k])  
    20.                 dst[k] = dst[u] + edge[u][k];             
    21.         }  
    22.     }  
    23. }  
    例1:给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s,终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
    输入:输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数s,t;起点s,终点 t。n和m为 0 时输入结束。(1<n<=1000, 0<m<100000, s != t)
    输出:输出一行,有两个数, 最短距离及其花费。
    分析:由于每条边有长度d和花费p,最好构建边结构体存放,此外可以使用邻接链表,使用邻接链表时需要将上面的核心代码修改几个地方:

    1,初始化dst[]时使用结点1的邻接链表;
    2,更新最短路径数组时,k的范围由1~n变为1~edge[u].size()。先采用邻接矩阵解决此题,再使用邻接表解决此题,两种方法的思路都一样:初始化邻接矩阵或邻接链表,并
    初始化最短路径数组dst ----> n-1轮边的松弛中,先找到离新源点最近的中心点u,之后根据中心点u为转折点来更新路径数组。

    使用邻接矩阵求解:

    1. /***对于无向图,输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数s,t;起点s,终点 t。***/  
    2. /***n和m为 0 时输入结束。(1<n<=1000, 0<m<100000, s != t)     输出:输出一行,有两个数, 最短距离及其花费。***/  
    3. #include <iostream>  
    4. #include <iomanip>  
    5. using namespace std;  
    6. #define nmax 1001  
    7. #define inf 99999999  
    8. struct Edge{  
    9.     int len;  
    10.     int cost;  
    11. };  
    12. Edge edge[nmax][nmax];  
    13. int dst[nmax], spend[nmax], book[nmax], n, m, stNode, enNode;  
    14. int main(){  
    15.     while(cin >> n >> m && n != 0 && m != 0){  
    16.         int a, b, i, j;  
    17.         //构建邻接矩阵和最短路径数组  
    18.         for(i = 1; i <= n; i++){  
    19.             for(j = 1; j <= n; j++){  
    20.                 edge[i][j].cost = 0;  
    21.                 edge[i][j].len = inf;  
    22.             }  
    23.             edge[i][i].len = 0;  
    24.         }  
    25.         while(m--){  
    26.             cin >> a >> b;  
    27.             cin >> edge[a][b].len >> edge[a][b].cost;  
    28.             edge[b][a].len = edge[a][b].len;  
    29.             edge[b][a].cost = edge[a][b].cost;  
    30.         }  
    31.         cin >> stNode >> enNode;  
    32.         for(i = 1; i <= n; i++){  
    33.             dst[i] = edge[stNode][i].len;  
    34.             spend[i] = edge[stNode][i].cost;  
    35.         }  
    36.         memset(book, 0, sizeof(book));  
    37.         book[stNode] = 1;  
    38.         //开始迪杰斯特拉算法,进行剩余n-1次松弛  
    39.         int k;  
    40.         for(k = 1; k <= n-1; k++){  
    41.             //找离源点最近的顶点u  
    42.             int minNode, min = inf;  
    43.             for(i = 1; i <= n; i++){  
    44.                 if(book[i] == 0 && min > dst[i] /* || min == dst[i]&& edge[stNode][min].cost > edge[stNode][i].cost*/){  
    45.                     min = dst[i];  
    46.                     minNode = i;  
    47.                 }  
    48.             }  
    49.             //cout << setw(2) << minNode;  
    50.             book[minNode] = 1;//易错点1,错写成book[i]=1  
    51.             //以中心点u为转折点来更新路径数组和花费数组  
    52.             for(i = 1; i <= n; i++){  
    53.                 if(book[i] == 0 && dst[i] > dst[minNode] + edge[minNode][i].len || dst[i] == dst[minNode] + edge[minNode][i].len && spend[i] > spend[minNode] + edge[minNode][i].cost){  
    54.                     dst[i] = dst[minNode] + edge[minNode][i].len;//易错点2,错写成dst[i]+  
    55.                     spend[i] = spend[minNode] + edge[minNode][i].cost;  
    56.                 }  
    57.             }  
    58.         }  
    59.         cout << dst[enNode] << setw(3) << spend[enNode] << endl;  
    60.     }  
    61.     return 0;  
    62. }  
    程序运行结果如下:



    使用邻接链表求解:

    1. /***对于无向图,输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数s,t;起点s,终点 t。***/  
    2. /***n和m为 0 时输入结束。(1<n<=1000, 0<m<100000, s != t)     输出:输出一行,有两个数, 最短距离及其花费。***/  
    3. #include <iostream>  
    4. #include <iomanip>  
    5. #include <vector>  
    6. using namespace std;  
    7. #define nmax 1001  
    8. #define inf 99999999  
    9. struct Edge{  
    10.     int len;  
    11.     int cost;  
    12.     int next;  
    13. };  
    14. vector<Edge> edge[nmax];  
    15. int dst[nmax], spend[nmax], book[nmax], n, m, stNode, enNode;  
    16. int main(){  
    17.     while(cin >> n >> m && n != 0 && m != 0){  
    18.         int a, b, i, j;  
    19.         //构建邻接表和最短路径数组  
    20.         for(i = 1; i <= n; i++) edge[i].clear();  
    21.         while(m--){  
    22.             Edge tmp;  
    23.             cin >> a >> b;  
    24.             tmp.next = b;  
    25.             cin >> tmp.len >> tmp.cost;  
    26.             edge[a].push_back(tmp);  
    27.             tmp.next = a;  
    28.             edge[b].push_back(tmp);  
    29.         }  
    30.         cin >> stNode >> enNode;  
    31.         for(i = 1; i <= n; i++) dst[i] = inf; //注意2,别忘记写此句来初始化dst[]  
    32.         for(i = 0; i < edge[stNode].size(); i++){//注意1,从下标0开始存元素,误写成i <= edge[stNode].size()  
    33.             dst[edge[stNode][i].next] = edge[stNode][i].len;  
    34.             //cout << dst[2] << endl;  
    35.             spend[edge[stNode][i].next] = edge[stNode][i].cost;  
    36.         }  
    37.         memset(book, 0, sizeof(book));  
    38.         book[stNode] = 1;  
    39.         //开始迪杰斯特拉算法,进行剩余n-1次松弛  
    40.         int k;  
    41.         for(k = 1; k <= n-1; k++){  
    42.             //找离源点最近的顶点u  
    43.             int minnode, min = inf;  
    44.             for(i = 1; i <= n; i++){  
    45.                 if(book[i] == 0 && min > dst[i] /* || min == dst[i]&& edge[stnode][min].cost > edge[stnode][i].cost*/){  
    46.                     min = dst[i];  
    47.                     minnode = i;  
    48.                 }  
    49.             }  
    50.             //cout << setw(2) << minnode;  
    51.             book[minnode] = 1;//易错点1,错写成book[i]=1  
    52.             //以中心点u为转折点来更新路径数组和花费数组  
    53.             for(i = 0; i < edge[minnode].size(); i++){  
    54.                 int t = edge[minnode][i].next;//别忘了加此句,表示与结点minnode相邻的点  
    55.                 if(book[t] == 0 && dst[t] > dst[minnode] + edge[minnode][i].len || dst[t] == dst[minnode] + edge[minnode][i].len && spend[t] > spend[minnode] + edge[minnode][i].cost){  
    56.                     dst[t] = dst[minnode] + edge[minnode][i].len;  
    57.                     spend[t] = spend[minnode] + edge[minnode][i].cost;  
    58.                 }  
    59.             }  
    60.         }  
    61.         cout << dst[enNode] << setw(3) << spend[enNode] << endl;  
    62.     }  
    63.     return 0;  
    64. }  
    程序运行结果如下:


    使用邻接表时,注意更新dst[],book[]时要使用邻接表元素对应下标中的next成员,而涉及到权值加减时时需要使用邻接表中的对应下标来取得权值;而使用邻接矩阵就没这么多顾虑了,因为这时候邻接矩阵对应下标和dst[]要更新元素的下标正好一致,都是从1开始编号。



    4),Bellman-Ford算法(解决负权边,解决单源最短路径,前几种方法不能求含负权边的图)::时间复杂度O(nm),空间复杂度O(m)
    主要思想:对所有的边进行n-1轮松弛操作,因为在一个含有n个顶点的图中,任意两点之间的最短路径最多包含n-1边。换句话说,第1轮在对所有的边进行松弛后,得到的是从1号顶点只能经过一条边到达其余各定点的最短路径长度。第2轮在对所有的边进行松弛后,得到的是从1号顶点只能经过两条边到达其余各定点的最短路径长度,......
    以下是图示:


    此外,Bellman_Ford还可以检测一个图是否含有负权回路:如果在进行n-1轮松弛后仍然存在dst[e[i]] > dst[s[i]]+w[i]。算法核心代码如下:

    1. #define inf 999999999  
    2. for(i = 1; i <= n; i++) dst[i] = inf;  
    3. dst[1] = 0;  
    4. for(k = 1; k <= n-1; k++){  
    5.     for(i = 1; i <= m; i++){  
    6.         if(dst[e[i]] > dst[s[i]] + w[i])  
    7.             dst[e[i]] = dst[s[i]] + w[i];  
    8.     }  
    9. }  
    10. //检测负权回路  
    11. flag = 0;  
    12. for(i = 1; i <= m; i++){  
    13.     if(dst[e[i]] > dst[s[i]] + w[i])  
    14.         flag = 1;  
    15. }  
    16. if(flag) cout << "此图含有负权回路";  
    例1:对图示中含负权的有向图,输出从结点1到各结点的最短路径,并判断有无负权回路。

    1. /***先输入n,m,分别表结点数和边数,之后输入m个三元组,各表起点,终点,边权,输出1号结点到各结点的最短路径****/  
    2. #include <iostream>  
    3. #include <iomanip>  
    4. using namespace std;  
    5. #define nmax 1001  
    6. #define inf 99999999  
    7. int n, m, s[nmax], e[nmax], w[nmax], dst[nmax];  
    8. int main(){  
    9.     while(cin >> n >> m && n != 0 && m != 0){  
    10.         int i, j;  
    11.         //初始化三个数组:起点数组s[],终点数组e[],权值数组w[],最短路径数组dst[]  
    12.         for(i = 1; i <= m; i++)  
    13.             cin >> s[i] >> e[i] >> w[i];  
    14.         for(i = 1; i <= n; i++)  
    15.             dst[i] = inf;  
    16.         dst[1] = 0;  
    17.         //使用Bellman_Ford算法  
    18.         for(j = 1; j <= n-1; j++){  
    19.             for(i = 1; i <= m; i++){  
    20.                 if(dst[e[i]] > dst[s[i]] + w[i])  
    21.                     dst[e[i]] = dst[s[i]] + w[i];  
    22.             }  
    23.         }  
    24.         //测试是否有负权回路并输出  
    25.         int flag = 0;  
    26.         for(i = 1; i <= m; i++)  
    27.             if(dst[e[i]] > dst[s[i]] + w[i])  
    28.                 flag = 1;  
    29.         if(flag) cout << "此图含有负权回路\n";  
    30.         else{  
    31.             for(i = 1; i <= n; i++){  
    32.                 if(i == 1)  
    33.                     cout << dst[i];  
    34.                 else   
    35.                     cout << setw(3) << dst[i];  
    36.             }  
    37.             cout << endl;  
    38.         }  
    39.     }  
    40.     return 0;  
    41. }  
    程序运行结果如下:

    原文:http://blog.csdn.net/qibofang/article/details/51594673#

    展开全文
  • 前言 今天将给大家介绍的是图论算法中的另外一个基础部分——最短路径算法;其中又分为无权最短路径,单源最短路径,具有负边的最短路径以及无圈图等;而这次将介绍常见的两个——无权最短路径以及单源最短路径。接...
  • 单源最短路径算法,包括BellmanFord算法,有向无环图中的单源最短路径算法和Dijkstra算法
  • 地图最短路径算法

    2019-03-24 23:28:35
    最短路径算法,做了堆优化有测试用例,可以随机生成地图,地图中的数字代表的是该点的高度,高度差为两点的距离

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,671
精华内容 10,268
关键字:

最短路径算法