zoukankan      html  css  js  c++  java
  • c++最短路经典问题

    一提起最短路,各位oier会想到什么呢?

    floyd,spfa,dij,或是bellman-ford?

    其实,只要学会一种算法,大部分最短路问题就能很快解决了。

    他就是堆优化的dijkstra。

    首先,先讲一下dij是怎么求最短路的。

    Dijkstra是基于一种贪心的策略,首先用数组dis记录起点到每个结点的最短路径,再用一个数组保存已经找到最短路径的点

    然后,从dis数组选择最小值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点记为已经找到最短路

    此时完成一个顶点,再看这个点能否到达其它点(记为v),将dis[v]的值进行更新

    不断重复上述动作,将所有的点都更新到最短路径

    这种算法实际上是O(n^2)的时间复杂度,但我们发现在dis数组中选择最小值时,我们可以用一些数据结构来进行优化。

    其实我们可以用STL里的堆来进行优化,堆相对于线段树以及平衡树有着常数小,码量小等优点,并且堆的一个妙妙的性质就是可以在nlogn的时限内满足堆顶是堆内元素的最大(小)值,之不正是我们要的嘛?

    但是呢,dij处理不了负边,所以当题目出现负边时,dij就不能用了。

    但反过来说,只要题目没负边,SPFA是一定会被卡的!

    下面上代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 10005
    #define maxm 500005
    #define INF  1234567890
    inline int read()
    {
        int x=0,k=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
        while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
        return x*k;
    }
    struct Edge
    {
        int u,v,w,next;
    }e[maxm];
    int head[maxn],cnt,n,m,s,vis[maxn],dis[maxn];
    struct node
    {
        int w,now;
        inline bool operator <(const node &x)const
        //重载运算符把最小的元素放在堆顶(大根堆)
        {
            return w>x.w;//这里注意符号要为'>'
        }
    };
    priority_queue<node>q;
    //优先队列,其实这里一般使用一个pair,但为了方便理解所以用的结构体
    inline void add(int u,int v,int w)
    {
        e[++cnt].u=u;
        //这句话对于此题不需要,但在缩点之类的问题还是有用的
        e[cnt].v=v;
        e[cnt].w=w;
        e[cnt].next=head[u];
        //存储该点的下一条边
        head[u]=cnt;
        //更新目前该点的最后一条边(就是这一条边)
    }
    //链式前向星加边
    void dijkstra()
    {
        for(int i=1;i<=n;i++)
        {
            dis[i]=INF;
        }
        dis[s]=0;
        //赋初值
        q.push((node){0,s});
        while(!q.empty())
        //堆为空即为所有点都更新
        {
            node x=q.top();
            q.pop();
            int u=x.now;
            //记录堆顶(堆内最小的边)并将其弹出
            if(vis[u]) continue; 
            //没有遍历过才需要遍历
            vis[u]=1;
            for(int i=head[u];i;i=e[i].next)
            //搜索堆顶所有连边
            {
                int v=e[i].v;
                if(dis[v]>dis[u]+e[i].w)
                {
                    dis[v]=dis[u]+e[i].w;
                    //松弛操作
                    q.push((node){dis[v],v});
                    //把新遍历到的点加入堆中
                }
            }
        }
    }
    int main()
    {
        n=read(),m=read(),s=read();
        for(int i=1,x,y,z;i<=m;i++)
        {
            x=read(),y=read(),z=read();
            add(x,y,z);
        }
        dijkstra();
        for(int i=1;i<=n;i++)
        {
            printf("%d ",dis[i]);
        }
        return 0;
    }

    谢谢大家!

  • 相关阅读:
    Winform自定义窗体样式,实现标题栏可灵活自定义
    肿瘤转录组数分析CRN:Cancer RNA-Seq Nexus
    TCGA系列--miRNA数据分析
    TCGA系列--甲基化神器mexpress
    R:reshape2包中的melt
    TCGA系列--GDCRNATools
    R软件中排序:sort(),rank(),order()
    TCGA系列--TCGA长链非编码RNA的可视化工具TANRIC
    记一次RabbitMQ解决分布式事务问题
    RabbitMQ整合Spring Booot【死信队列】
  • 原文地址:https://www.cnblogs.com/mxrmxr/p/9851795.html
Copyright © 2011-2022 走看看