Dijstra单源最短路算法

Dijistra算法求单源最短路径

参考文章 :wiki的博文

算法思想:

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

算法步骤:

a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。

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

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

d.重复步骤b和c直到所有顶点都包含在S中。

基本实现思想:

创建一个二维数组,用来存储数据边的长度。

创建两个数组一个S,一个 U ,S用来存储已求出最短路径的集合,U用来存储未求出最短路径的集合

直到S中包含所有的顶点,算法结束。

#include <iostream>
using namespace std;
int main()
{
    int e[10][10];//用来存储两点之间的边的长度
    int dis[10];//用当前顶点到起始顶点的当前最短路径
    int book[10]={0};//标记当前顶点是否找到当前最短路径
    int inf=999;//表示路径的最大值
    int n,m,start,min,u;
    cout<<"输入顶点数和边数"<<endl;
    cin>>n>>m;
    //初始化
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        if(i==j) e[i][j]=0;
        else e[i][j]=inf;
    }
    //输入边的相关信息
    for(int i=0;i<m;i++)
    {
        int a,b,value;
        cin>>a>>b>>value;
        e[a][b]=value;
    }
    cout<<"输入起点的顶点"<<endl;
    cin>>start;
  //初始化各顶点到start的距离
    for(int i=1;i<=n;i++)
        dis[i]=e[start][i];
    book[start]=1;//将start顶点最先纳入到集合S中去
    //dijstra核心算法
 for(int i=1;i<=n-1;i++)//循环n-1次,
    {
        //找到离start最近的顶点
        min=inf;//用来比较得到最近的顶点
        for(int t=1;t<=n;t++)
            for(int v=1;v<=n;v++)
            if(!book[v]&&dis[v]<min)
            {
               min=dis[v];
                u=v;//找出最小值的顶点
            }
            //将最小值的定点加入到最短路径中
            book[u]=1;
            //更改U集合中其中的点到start的路径的长度
            for(int i=1;i<=n;i++)
            {
                if(!book[i]&&dis[i]>dis[u]+e[u][i])
                {
                    //交换值
                    dis[i]=dis[u]+e[u][i];
                }
            }

    }
//输出各顶点到start顶点的最短路径
   for(int i=1;i<=n;i++)
    {
        cout<<start<<"-->"<<i<<"的距离为: "<<dis[i]<<endl;
    }
}

测试数据


    6 9
    1 2 1
    1 3 12
    2 3 9
    2 4 3
    3 5 5
    4 3 4
    4 5 13
    4 6 15
    5 6 4

运行结果是

通过上面的代码我们可以看出,这个算法的时间复杂度是 O(N2)。其中每次找到离 1 号顶点最近的顶点的时间复杂度是 O(N),这里我们可以用“堆”(以后再说)来优化,使得这一部分的时间复杂度降低到 O(logN)。另外对于边数 M 少于 N2 的稀疏图来说(我们把 M 远小于 N2 的图称为稀疏图,而 M 相对较大的图称为稠密图),我们可以用邻接表(这是个神马东西?不要着急,下周再仔细讲解)来代替邻接矩阵,使得整个时间复杂度优化到 O( (M+N)logN )。请注意!在最坏的情况下 M 就是 N2,这样的话 MlogN 要比 N2 还要大。但是大多数情况下并不会有那么多边,因此(M+N)logN 要比 N2 小很多。





猜你喜欢

转载自blog.csdn.net/laoyao_legend/article/details/80882028
今日推荐