----------------------------------------第一次写博客的心情分割线---------------------------------------------
啥是最短路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)