zoukankan      html  css  js  c++  java
  • 最短路

    ----------------------------------------第一次写博客的心情分割线---------------------------------------------

    啥是最短路QAQ???

    最短路:用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。——百度百科

    从一点到其他任一点有多条路径,问哪一种走法最省时省力,就是最短路问题。

    常用的求最短路的算法有三种:Dijkstra算法,Floyd算法,SPFA算法

    一、Dijkstra算法

    \\如果我是DJ你會愛我嗎你會愛我嗎 呸 >>博主是個fzl(=v=)\\

    算法思想:贪心

      从起点开始每次扩展一个距离最短的点,再以该点为中心,更新起点到其他所有点的距离

      距离最短的点:可以用优先队列实现

    试用范围:不带负边权的有向图或无向图

    priority_queue< pair<int,int> >q;
    void dijkstra(int s)//s:起点 
    {
        memset(dis,0x3f,sizeof(dis));//初始化dis[i]为正无穷 
        memset(v,0,sizeof(v));//标记为未访问过
        d[s]=0; 
        q.push(make_pair(0,1));
        while(q.size())//此处也可以写成while(!q.empty())
        {
            int x=q.top().second;//取出堆顶 
            q.pop();
            if(v[x])
                continue;//选择一个 未标记的点
            v[x]=1;//结点标记
            for(int i=head[x];i;i=nex[i])//邻接表 扫描出边
            {
                int y=ver[i],z=edge[i];
                if(d[y]>d[x]+z)
                {
                    d[y]=d[x]+z;
                    q.push(make_pair(-d[y],y));
                }
            }
        }
    }

    关于代码最后一行"q.push(make_pair(-d[y],y))"

    可以发现这里插入的是-d[y]而不是d[y]

    因为优先队列默认大根堆 而插入dis的相反数恰好可以改写这个性质

    二、Floyd算法

    算法思想:DP

      转移方程:d[i][j]=min(d[i][j],d[i][k]+d[k][i])

    适用范围:没有负环的图

    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
             for(int j=1;j<=n;j++)
             {
                 if(i!=j&&i!=k&&j!=k)
                 d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
             }
        }
    }

    运用了三层循环 因此这个代码的时间复杂度为n^3

    注意 d数组要初始化为极大值哦!

    三、SPFA算法

    基本算法:

      ①设立队列

      ②每次取出队首,标记该点出队,并从该点对与该点相连的点进行松弛操作,如果松弛成功,更新

      ③若松弛成功且新的点不在队列中,新结点入队

      ④循环②③直到队列为空

    #include<queue>
    using namespace std; 
    void SPFA()
    {
        queue <int> q;
        memset(d,0x3f,sizeof(d));
        memset(v,0,sizeof(v));
        d[1]=0;
        v[1]=1;
        q.push(1);
        while(!q.empty())
        {
            int x=q.front();//取出队头
            q.pop();//pop!!!
            v[x]=0;
            for(int i=head[x];i;i=nex[i])
            {
                int y=ver[i],z=edge[i];
                if(d[y]>d[x]+z)
                {
                    d[y]=d[x]+z;//不断更新 
                    if(!v[y])
                        q.push(y),v[y]=1;
                }
            }
        }
    }

    每次入队需要先满足三角不等式d[y]>d[x]+z

    一个结点可能多次出入队列 最终使所有点收敛到全部满足三角不等式的状态

    该算法的时间复杂度会小于O(n*m)

  • 相关阅读:
    【SCOI 2011】 糖果
    【POJ 3159】 Candies
    【POJ 1716】 Integer Intervals
    【POJ 2983】 Is the information reliable?
    【POJ 1364】 King
    【POJ 1201】 Intervals
    【POJ 1804】 Brainman
    6月10日省中提高组题解
    【POJ 3352】 Road Construction
    【POJ 1144】 Network
  • 原文地址:https://www.cnblogs.com/WJill/p/11206980.html
Copyright © 2011-2022 走看看