zoukankan      html  css  js  c++  java
  • 单源最短路径——dijkstra算法

    dijkstra算法与prim算法的区别

     

    1.先说说prim算法的思想:

    众所周知,prim算法是一个最小生成树算法,它运用的是贪心原理(在这里不再证明),设置两个点集合,一个集合为要求的生成树的点集合A,另一个集合为未加入生成树的点B,它的具体实现过程是:

    第1步:所有的点都在集合B中,A集合为空。

    第2步:任意以一个点为开始,把这个初始点加入集合A中,从集合B中减去这个点(代码实现很简单,也就是设置一个标示数组,为false表示这个点在B中,为true表示这个点在A中),寻找与它相邻的点中路径最短的点,如后把这个点也加入集合A中,从集合B中减去这个点(代码实现同上)。

    第3步:集合A中已经有了多个点,这时两个集合A和B,只要找到A集合中的点到B集合中的点的最短边,可以是A集合中的与B集合中的点的任意组合,把这条最短边有两个顶点,把在集合B中的顶点加入到集合A中,(代码实现的时候有点技巧,不需要枚举所有情况,也就是更新操作)。

    第4步:重复上述过程。一直到所有的点都在A集合中结束。

    2.说说dijkstra算法的过程:

    这个算法的过程有比prim算法的过程稍微多一点点步骤,但是思想确实巧妙的,也是贪心原理,它的目的是求某个源点到目的点的最短距离,总的来说,dijkstra算法也就是求某个源点到目的点的最短路,求解的过程也就是求源点到整个图的最短距离,次短距离,第三短距离等等(这些距离都是源点到某个点的最短距离)。。。。。求出来的每个距离都对应着一个点,也就是到这个点的最短距离,求的也就是原点到所有点的最短距离,并且存在了一个二维数组中,最后给出目的点就能直接通过查表获得最短距离。

    第1步:以源点(假设是s1)为开始点,求最短距离,如何求呢? 与这个源点相邻的点与源点的距离全部放在一个数组dist[]中,如果不可达,dist[]中为最大值,这里说一下,为什么要是一维数组,原因是默认的是从源点到这个一维数组下标的值,只需要目的点作为下标就可以,这时从源点到其他点的最短的“一”条路径有了,只要选出dist[]中最小的就行(得到最短路径的另一个端点假设是s2)。

    第2步:这时要寻找源点(假设是s1)到另外点的次短距离,这个距离或者是dist[]里面的值,或者是从第1步中选择的那个最短距离 + 从找到点(假设是s2)出发到其他点的距离(其实这里也是一个更新操作,更新的是dist[]里面的值),如果最短距离 + 从这点(假设是s2)到其他点的距离,小于dist[]里面的值,就可以更新dist[]数组了,然后再从dist[]数组中选一个值最小的,也就是第“二”短路径(次短路径)。

    第3步:寻找第“三”短路径,这时同上,第二短路径的端点(s3)更新与之相邻其他的点的dist[]数组里面的值。

    第4步:重复上述过程n - 1次(n指的是节点个数),得出结果,其实把源点到所有点的最短路径求出来了,都填在了dist[]表中,要找源点到哪个点的最短路,就只需要查表了。

    /*Dijkstra求单源最短路径 2010.8.26*/
     
    #include <iostream>
    #include<stack>
    #define M 100
    #define N 100
    using namespace std;
    
    typedef struct node
    {
        int matrix[N][M];      //邻接矩阵 
        int n;                 //顶点数 
        int e;                 //边数 
    }MGraph; 
    
    void DijkstraPath(MGraph g,int *dist,int *path,int v0)   //v0表示源顶点 
    {
        int i,j,k;
        bool *visited=(bool *)malloc(sizeof(bool)*g.n);
        for(i=0;i<g.n;i++)     //初始化 
        {
            if(g.matrix[v0][i]>0&&i!=v0)
            {
                dist[i]=g.matrix[v0][i];
                path[i]=v0;     //path记录最短路径上从v0到i的前一个顶点 
            }
            else
            {
                dist[i]=INT_MAX;    //若i不与v0直接相邻,则权值置为无穷大 
                path[i]=-1;
            }
            visited[i]=false;
            path[v0]=v0;
            dist[v0]=0;
        }
        visited[v0]=true;
        for(i=1;i<g.n;i++)     //循环扩展n-1次 
        {
            int min=INT_MAX;
            int u;
            for(j=0;j<g.n;j++)    //寻找未被扩展的权值最小的顶点 
            {
                if(visited[j]==false&&dist[j]<min)
                {
                    min=dist[j];
                    u=j;        
                }
            } 
            visited[u]=true;
            for(k=0;k<g.n;k++)   //更新dist数组的值和路径的值 
            {
                if(visited[k]==false&&g.matrix[u][k]>0&&min+g.matrix[u][k]<dist[k])
                {
                    dist[k]=min+g.matrix[u][k];
                    path[k]=u; 
                }
            }        
        }    
    }
    
    void showPath(int *path,int v,int v0)   //打印最短路径上的各个顶点 
    {
        stack<int> s;
        int u=v;
        while(v!=v0)
        {
            s.push(v);
            v=path[v];
        }
        s.push(v);
        while(!s.empty())
        {
            cout<<s.top()<<" ";
            s.pop();
        }
    } 
    
    int main(int argc, char *argv[])
    {
        int n,e;     //表示输入的顶点数和边数 
        while(cin>>n>>e&&e!=0)
        {
            int i,j;
            int s,t,w;      //表示存在一条边s->t,权值为w
            MGraph g;
            int v0;
            int *dist=(int *)malloc(sizeof(int)*n);
            int *path=(int *)malloc(sizeof(int)*n);
            for(i=0;i<N;i++)
                for(j=0;j<M;j++)
                    g.matrix[i][j]=0;
            g.n=n;
            g.e=e;
            for(i=0;i<e;i++)
            {
                cin>>s>>t>>w;
                g.matrix[s][t]=w;
            }
            cin>>v0;        //输入源顶点 
            DijkstraPath(g,dist,path,v0);
            for(i=0;i<n;i++)
            {
                if(i!=v0)
                {
                    showPath(path,i,v0);
                    cout<<dist[i]<<endl;
                }
            }
        }
        return 0;
    }

    测试数据:

      

      运行结果:

      

  • 相关阅读:
    4.9版本的linux内核中实时时钟芯片pt7c4338的驱动源码在哪里
    4.9版本的linux内核中eeprom存储芯片at24c512的驱动源码在哪里
    4.9版本的linux内核中温度传感器adt7461的驱动源码在哪里
    4.9版本linux内核的ina220电流检测芯片源码在哪里
    nxp的layerscape系列芯片中的rcw指定了一些什么信息
    openwrt的编译系统是如何制作根文件系统的
    openwrt的编译系统在哪里对程序进行开机自动启动配置
    makefile中的word函数作用是什么
    jquery 动态增加table行,动态删除table行
    使用jQuery创建可删除添加行的动态表格,超级简单实用的方法
  • 原文地址:https://www.cnblogs.com/scarecrow-blog/p/3632782.html
Copyright © 2011-2022 走看看