最短路

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

啥是最短路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)

原文地址:https://www.cnblogs.com/WJill/p/11206980.html