zoukankan      html  css  js  c++  java
  • 单源最短路(dijkstra)

    (*^▽^*),忽然发现一个惊天大秘密!!(好吧也有可能是因为之前太菜所以没有发现qwq)

    那就是!dij 和prim 的板子好像是一样的哎 (*╹▽╹*)

    就是说他们的思想好像是一样的,而且前面的内容,不管是变量的设置,还是queue的设置,好像..都差不多??

    看一下哈:

    prim:

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m;
    vector<pair<int,int> > v[1020000];
    
    struct node{
        int x,w;
        node(int a=0,int b=0)
        {
            x=a;
            w=b;
        }
    }; 
    
    void add(int x,int y,int z)
    {
        v[x].push_back(make_pair(y,z)); 
    }
    
    bool operator < (const node &a,const node &b)
    {
        return a.w >b.w ;
    }
    
    priority_queue<node> q;
    
    int dis[1020000];
    bool vis[1020000];
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            add(a,b,c);
            add(b,a,c);
        }
        
        memset(dis,0x3f,sizeof(dis));
        
        dis[1]=0;
        q.push(node(1,dis[1]));
        int sum=0;
        int tot=1;
        
        
        while(!q.empty())
        {
            int x=q.top().x;
            q.pop();
            if(vis[x]) continue;
            vis[x]=1;
            tot++;
            sum+=dis[x];
            for(int i=0;i<v[x].size();i++)
            {
                int y=v[x][i].first;
                int z=v[x][i].second;
                if(dis[y]>z)
                {
                    dis[y]=z;
                    q.push(node(y,dis[y]));
                 } 
            }
         } 
         
         if(tot<n-1) cout<<"orz";
         else cout<<sum;
         return 0;
        
        
    }

    dij:

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m,s;
    vector<pair<int,int> > v[1020000];
    int d[1020000];
    bool vis[1020000];
    
    struct node{
        int x,w;
        node(int a=0,int b=0)
        {
            x=a;
            w=b;
        }
    };
    
    priority_queue<node> q;
    
    bool operator < (const node &a,const node &b)
    {
        return a.w >b.w ;
    }
    
    void add(int x,int y,int z)
    {
        v[x].push_back(make_pair(y,z));
    } 
    
    int main()
    {
        cin>>n>>m>>s;
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            add(a,b,c);
    //        add(b,a,c);
        }
        
        memset(d,0x3f,sizeof(d));
        
        d[s]=0;
        q.push(node(s,d[s]));
        while(!q.empty())
        {
            int x=q.top().x;
            q.pop();
            if(vis[x]) continue;
            vis[x]=1;
            for(int i=0;i<v[x].size();i++)
            {
                int y=v[x][i].first;
                int w=v[x][i].second;
                if(d[y]>d[x]+w)
                {
                    d[y]=d[x]+w;
                    q.push(node(y,d[y])); 
                }
            }
         } 
         
         for(int i=1;i<=n;i++) cout<<d[i]<<" ";
         return 0; 
        
    }

    主要看前面!!是不是几乎一样?!

    不一样的点其实只有一下几个:
    1.访问x节点的子节点y时,对于d[x]的修改方式不同

    2.在取出队首元素标记访问的时候,prim因为最后要判断到底可不可以生成树,所以还要多加一步记录访问节点个数,但是dij却不需要

    好啦,其实prim和dij好像只有以上两点区别,详细介绍还是看下面吧qwq

    这里介绍 Dijkstra 算法,它是一个应用最为广泛的、名气也是最大的单源最短路径算法Dijkstra 算法有一定的局限性:它所处理的图中不能有负权边

    「前提:图中不能有负权边」

    换句话说,如果一张图中,但凡有一条边的权值是负值,那么使用 Dijkstra 算法就可能得到错误的结果不过,在实际生活中所解决的问题,大部分的图是不存在负权边的

    如:有一个路线图,那么从一点到另外一点的距离肯定是一个正数,所以,虽然 Dijkstra 算法有局限性,但是并不影响在实际问题的解决中非常普遍的来使用它

    看如下实例:

    (1)初始

       

    左边是一张连通带权有向图,右边是起始顶点 0 到各个顶点的当前最短距离的列表,起始顶点 0 到自身的距离是 0

    (2)将顶点 0 进行标识,并作为当前顶点

       

    对当前顶点 0 的所有相邻顶点依次进行松弛操作,同时更新列表从列表的未标识顶点中找到当前最短距离最小的顶点,即 顶点 2,就可以说,起始顶点 0 到顶点 2 的最短路径即 0 -> 2

    因为:图中没有负权边,即便存在从顶点 1 到顶点 2 的边,也不可能通过松弛操作使得从起始顶点 0 到顶点 2 的距离更小

    图中没有负权边保证了:对当前顶点的所有相邻顶点依次进行松弛操作后,只要能从列表的未标识顶点中找到当前最短距离最小的顶点,就能确定起始顶点到该顶点的最短路径

    (3)将顶点 2 进行标识,并作为当前顶点

       

        

       (4)对当前顶点 2 的相邻顶点 1 进行松弛操作,同时更新列表

       

    (5)对当前顶点 2 的相邻顶点 4 进行松弛操作,同时更新列表

       

       

    (6)对当前顶点 2 的相邻顶点 3 进行松弛操作,同时更新列表

       

       

       

    从列表的未标识顶点中找到当前最短距离最小的顶点,即 顶点 1,

    就可以说,起始顶点 0 到顶点 1 的最短路径即 0 -> 2 -> 1

    (7)将顶点 1 进行标识,并作为当前顶点

       

       

       

       

       

    (8)对当前顶点 1 的相邻顶点 4 进行松弛操作,同时更新列表

       

    从列表的未标识顶点中找到当前最短距离最小的顶点,即 顶点 4,就可以说,起始顶点 0 到顶点 4 的最短路径即 0 -> 2 -> 1 -> 4

    (9)将顶点 4 进行标识,并作为当前顶点

       

       

    当前顶点 4 没有相邻顶点,不必进行松弛操作

    从列表的未标识顶点中找到当前最短距离最小的顶点,即 顶点 3,就可以说,起始顶点 0 到顶点 3 的最短路径即 0 -> 2 -> 3

    (10)将顶点 3 进行标识,并作为当前顶点

       

       

       

    对当前顶点 3 的相邻顶点 4 进行松弛操作,发现不能通过松弛操作使得从起始顶点 0 到顶点 4 的路径更短,所以保持原有最短路径不变至此,列表中不存在未标识顶点,Dijkstra 算法结束,找到了一棵以顶点 0 为根的最短路径树

    Dijkstra 算法的过程总结:

    第一步:从起始顶点开始

    第二步:对当前顶点进行标识

    第三步:对当前顶点的所有相邻顶点依次进行松弛操作

    第四步:更新列表

    第五步:从列表的未标识顶点中找到当前最短距离最小

           的顶点,作为新的当前顶点

    第六步:重复第二步至第五步,直到列表中不存在未标识顶点

    Dijkstra 算法主要做两件事情:

    (1)从列表中找最值

    (2)更新列表

    显然,借助最小索引堆作为辅助数据结构,就可以非常容易地实现这两件事情

    最后,Dijkstra 算法的时间复杂度:O(E*logV)

    转自:https://blog.csdn.net/qq_35644234/article/details/60870719

    @ Ouyang_Lianjun

  • 相关阅读:
    苹果一体机发射Wi-Fi
    iphone 屏蔽系统自动更新,消除设置上的小红点
    data parameter is nil 异常处理
    copy与mutableCopy的区别总结
    java axis2 webservice
    mysql 远程 ip访问
    mysql 存储过程小问题
    mysql游标错误
    is not writable or has an invalid setter method错误的解决
    Struts2中关于"There is no Action mapped for namespace / and action name"的总结
  • 原文地址:https://www.cnblogs.com/yxr001002/p/14082024.html
Copyright © 2011-2022 走看看