zoukankan      html  css  js  c++  java
  • 数据结构之Dijkstra

    总感觉Dijkstra跟prim思路很像,现在仔细想想虽然都算的上贪心,但是Dijkstra比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集合中结束。

    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[]表中,要找源点到哪个点的最短路,就只需要查表了。

    附一道题:

     hdu1874

    #include<iostream>
    using namespace std;
    const int maxnum=1005;
    const int maxint=99999;
    int dist[maxnum];//起点到终点的距离
    int c[maxnum][maxnum];//用于储存两点之间的距离
    void Dijkstra(int S,int N,int * dist,int  c[maxnum][maxnum])
    {
        bool s[maxnum];//判断是否已加入集合S中
        //初始化起始点到其他点的距离
       for(int i=0;i<N;i++)
        {
            dist[i]=c[S][i];
            s[i]=0;
        }
         //起始点被标记,最短距离为0
        s[S]=1;
        dist[S]=0;
        //遍历剩下n-1个点

           for(int i=1;i<N;i++)
        {
            int u=S;
            int temp=maxint;
            //找出尚未标记的点中,与起始点距离最短的
            for(int j=0;j<N;j++)
                if(!s[j]&&dist[j]<temp)
                {
                    u=j;
                    temp=dist[j];
                }
            s[u]=1;
            //最难理解的地方:找到当前已于起始点联通的点的最短距离,随着每一次遍历,会更新,最终达到最短

           for(int k=0;k<N;k++)
                if(!s[k]&&dist[k]>dist[u]+c[u][k])
                {
                    dist[k]=dist[u]+c[u][k];
                }

        }

    }

     int main ()
    {
        int   N,M;
       while(cin>>N>>M)
       {
            int A,B,X;
            for(int i=0;i<N;i++)
               for(int j=0;j<N;j++)
                    c[i][j]=maxint;
            for(int i=1; i<=N; ++i)
               dist[i] = maxint;

              for(int i=0;i<M;i++)
            {
                cin>>A>>B>>X;
                if(X<c[A][B])
                {
                    c[A][B]=X;
                    c[B][A]=X;
                }
            }

           int S,E;
            cin>>S>>E;
            Dijkstra(S,N,dist,c);

             if(dist[E]==maxint)
                cout<<"-1"<<endl;
            else
                cout<<dist[E]<<endl;
        }
        return 0;
    }

  • 相关阅读:
    Linux(Centos7)下redis5安装、部署、开机自启
    请求*.html后缀无法返回json数据的问题
    Linux搭建图片服务器减轻传统服务器的压力(nginx+vsftpd)
    Centos7和Centos6防火墙开放端口配置方法(避坑教学)
    分享一个酷炫动态登录页面html
    分布式全文搜索解决方案
    PHP实现支付宝登录
    PHP发送短信
    PHP中发送qq邮件
    ES6新语法(二)
  • 原文地址:https://www.cnblogs.com/ACWQYYY/p/4375428.html
Copyright © 2011-2022 走看看