Dijkstra最短路径算法[贪心]

Dijkstra算法的标记和结构与prim算法的用法十分相似。它们两者都会从余下顶点的优先队列中选择下一个顶点来构造一颗扩展树。但千万不要把它们混淆了。它们解决的是不同的问题,因此,所操作的优先级也是以不同的方式计算的:Dijkstra算法比较路径的长度,因此必须把边的权重相加,而prim算法则直接比较给定的权重。

源最短路径问题
给定一个带权有向图 G=(V,E) ,其中每条边的权是一个非负实数。另外,还给定 V 中的一个顶点,称为源。现在我们要计算从源到所有其他各顶点的最短路径长度。这里的长度是指路上各边权之和。这个问题通常称为单源最短路径问题。

前面Bellman-Ford最短路径算法讲了单源最短路径的Bellman-Ford算法(动态规划算法)。这里介绍另外一个更常见的算法Dijkstra算法。

Dijkstra算法和 最小生成树Prim算法最小生成树算法非常类似,大家可以先熟悉下个算法。两个算法都是基于贪心算法。虽然Dijkstra算法相对来说比Bellman-Ford 算法更快,但是不适用于有负权值边的图,贪心算法决定了它的目光短浅。而Bellman-Ford 算法从全局考虑,可以检测到有负权值的回路。

这里模仿MST(Minimum Spanning Tree)的Prim算法,我们创建一个SPT(最短路径树),最初只包含源点。我们维护两个集合,一组已经包含在SPT(最短路径树)中的顶点S集合,另一组是未包含在SPT内的顶点T集合。每次从T集合中选择到S集合路径最短的那个点,并加入到集合S中,并把这个点从集合T删除。直到T集合为空为止。

举例说明,如下图所示的图:

S集合最初为空,然后选取源点0,S集合为 {0},源点到其它所有点的距离为 {0, 4, INF, INF, INF, INF, 8, INF} 。图中蓝色表示 SPT,迭代的过程如下

             

最终得到 SPT(最短路径树) 如下:

算法C++实现:

我们使用Boolean 数组sptSet[] (也有习惯用visit[]命名,表示是否访问过),来表示顶点是否为有SPT中。sptSet[v]=true,说明顶点v在SPT中。 dist[] 用来存储源点到其它所有点的最短路径。

#include<iostream>
#include<stdio.h>
#include<limits.h>
using namespace std;

const int V=9;
//从未包含在SPT的集合T中,选取一个到S集合的最短距离的顶点
int getMinIndex(int dist[V],bool sptSet[V])
{
    int min=INT_MAX,min_index;
    for(int v=0;v<V;v++)
    {
        if(!sptSet[v]&&dist[v]<min)
            min=dist[v],min_index=v;
    }
     return min_index;
}

//打印结果

void  printSolution(int dist[],int n)
{
    printf("Vertex Distance from Source\n");
    for(int i=0;i<V;i++)
        printf("%d\t\t %d\n",i,dist[i]);
}

//source 代表顶点
void dijkstra(int graph[V][V],int source)
{
    int dist[V];// 存储结果,从源点到 i的距离
    bool sptSet[V]; // sptSet[i]=true 如果顶点i包含在SPT中

    // 初始化. 0代表不可达
    for(int i=0;i<V;i++)
    {
        dist[i]=(graph[source][i]==0)?INT_MAX:graph[source][i];
        sptSet[i]=false;
    }
     // 源点,距离总是为0. 并加入SPT
    dist[source]=0;
    sptSet[source]=true;

    // 迭代V-1次,因此不用计算源点了,还剩下V-1个需要计算的顶点。
    for(int count=0;count<V-1;count++)
    {
     // u,是T集合中,到S集合距离最小的点,u开始在T集合中,然后加入到S集合
        int u=getMinIndex(dist,sptSet);
        // 加入SPT中
        sptSet[u]=true;
        for(int v=0;v<V;v++)
        {
        //满足以下4个条件
        //1. 点v还没有加入到spt中
        //2. 点u和v之间可达
        //3. 点u是可达的,距离不是无穷
        //4. 经过点u之后的距离小于直接到达点v的距离
            if(!sptSet[v]&&graph[u][v]&&dist[u]!=INT_MAX&&dist[u]+graph[u][v]<dist[v])
                dist[v]=dist[u]+graph[u][v];
        }
    }
    printSolution(dist,V);
}

int main()
{
    int graph[V][V]={ { 0, 4, 0, 0, 0, 0, 0, 8, 0 },
                    { 4, 0, 8, 0, 0, 0, 0, 11, 0 },
                    {0, 8, 0, 7, 0, 4, 0, 0, 2 },
                    { 0, 0, 7, 0, 9, 14, 0, 0, 0 },
                    { 0, 0, 0, 9, 0, 10, 0, 0, 0 },
                    { 0, 0, 4, 0, 10, 0, 2, 0, 0 },
                    { 0, 0, 0, 14, 0, 2, 0, 1, 6 },
                    { 8, 11, 0, 0, 0, 0, 1, 0, 7 },
                    { 0, 0, 2, 0, 0, 0, 6, 7, 0 }
                    };

    dijkstra(graph, 0);

    return 0;
}

运行结果如下:输出源点0到其它各个顶点的最短距离:

 

时间: 2024-10-25 23:29:36

Dijkstra最短路径算法[贪心]的相关文章

Dijkstra最短路径算法实现代码_C 语言

Dijkstra的最短路径算法是基于前驱顶点的最短路径计算的,整体上来讲还是比较简单的,下面是代码: 复制代码 代码如下: #include <iostream>#include <vector>#include <limits> void shortestpath( const std::vector <std::vector< short> >& paths, int from, std::vector< short>&a

[算法系列之三十]Dijkstra单源最短路径算法

单源最短路径问题 给定一个带权有向图 G=(V,E) ,其中每条边的权是一个非负实数.另外,还给定 V 中的一个顶点,称为源.现在我们要计算从源到所有其他各顶点的最短路径长度.这里的长度是指路上各边权之和.这个问题通常称为单源最短路径问题. 前面Bellman-Ford最短路径算法讲了单源最短路径的Bellman-Ford算法(动态规划算法).这里介绍另外一个更常见的算法Dijkstra算法. Dijkstra算法和 最小生成树Prim算法最小生成树算法非常类似,大家可以先熟悉下个算法.两个算法

python编写的最短路径算法_python

一心想学习算法,很少去真正静下心来去研究,前几天趁着周末去了解了最短路径的资料,用python写了一个最短路径算法.算法是基于带权无向图去寻找两个点之间的最短路径,数据存储用邻接矩阵记录.首先画出一幅无向图如下,标出各个节点之间的权值. 其中对应索引: A --> 0 B--> 1 C--> 2 D-->3 E--> 4 F--> 5 G--> 6 邻接矩阵表示无向图: 算法思想是通过Dijkstra算法结合自身想法实现的.大致思路是:从起始点开始,搜索周围的路径

最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)(转)

一,问题描述 在英文单词表中,有一些单词非常相似,它们可以通过只变换一个字符而得到另一个单词.比如:hive-->five:wine-->line:line-->nine:nine-->mine..... 那么,就存在这样一个问题:给定一个单词作为起始单词(相当于图的源点),给定另一个单词作为终点,求从起点单词经过的最少变换(每次变换只会变换一个字符),变成终点单词. 这个问题,其实就是最短路径问题. 由于最短路径问题中,求解源点到终点的最短路径与求解源点到图中所有顶点的最短路径复

python编写的最短路径算法

 本文给大家分享的是python 无向图最短路径算法:请各位大大指教,继续改进.(修改了中文字符串,使py2exe中文没烦恼),需要的朋友可以参考下     一心想学习算法,很少去真正静下心来去研究,前几天趁着周末去了解了最短路径的资料,用python写了一个最短路径算法.算法是基于带权无向图去寻找两个点之间的最短路径,数据存储用邻接矩阵记录.首先画出一幅无向图如下,标出各个节点之间的权值. 其中对应索引: A --> 0 B--> 1 C--> 2 D-->3 E--> 4

dijkstra标记算法-Dijkstra标记算法与Dijkstra算法的区别

问题描述 Dijkstra标记算法与Dijkstra算法的区别 请问离散数学中用Dijkstra标记算法求最短链与用Dijkstra算法求最短路径的联系 解决方案 dijkstra算法最短路径-Dijkstra算法Prim算法与Dijkstra算法的区别 解决方案二: 二者不是同一种算法吗?没有听说过迪杰斯特拉算法还分几种的啊.

图的遍历、拓扑排序、最短路径算法

1.DFS(深度优先搜索) 深度优先搜索算法(Depth-First-Search),是搜索算法的一种.它沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点.这一过程一直进行到已发现从源节点可达的所有节点为止.如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止.DFS 属于盲目搜索. 深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用

菜鸟问文件读取问题!dijkstra双向算法!

问题描述 小弟最近在研究dijkstra双向算法,原来是用C++设计的,运行成功.然后老师要求做界面,改成用C#编写,然后就不行了.大部分东西没有改,只是将一些写法改成了符合C#的格式,但是运行后(错误已全部调试完毕),点击"最短路径"后程序无反应,CPU100%,应该是进入了死循环,小弟怀疑在读取存着路径值的文件S2.txt时候出错,小弟C#比较烂,各位大哥大姐帮小弟看看吧,多谢了!下面是程序:privatevoidbutton1_Click(objectsender,EventAr

[算法系列之二十九]Bellman-Ford最短路径算法

单源最短路径 给定一个图,和一个源顶点src,找到从src到其它所有所有顶点的最短路径,图中可能含有负权值的边. Dijksra的算法是一个贪婪算法,时间复杂度是O(VLogV)(使用最小堆).但是迪杰斯特拉算法在有负权值边的图中不适用,Bellman-Ford适合这样的图.在网络路由中,该算法会被用作距离向量路由算法. Bellman-Ford也比迪杰斯特拉算法更简单和同时也适用于分布式系统.但Bellman-Ford的时间复杂度是O(VE),这要比迪杰斯特拉算法慢.(V为顶点的个数,E为边的