求最短路的常用3种算法
- SPFA
- Dijkstra
- floyd
SPAF
算法简介
这个算法全称是Shortest Path Faster Algorithm,该算法是西南交通大学段凡丁于1994年发表的;它可以在O(kE)的时间复杂度内求出源点到其他所有点的最短路径,其中k为所有顶点进队的平均次数,可以证明k一般小于等于2,可以处理负边,但无法处理带负环的图(负环和负边不是一个概念);
算法分析
1:队列在这个算法里面起了很大的作用,先将起始点压入队列,然后不断进行松弛操作,(每次都是以队列中的点所有边所到的终点进行松弛),松弛操作完就出队,最终队列为空得到起始点到个个点的最短路
2:关于松弛操作,其核心是比较两边之和一条边的情况,如果两边和小些,则用这两条边的结果替换原来的大边,最终得到最短的一条路
算法代码模板如下
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define fo(a,b,c) for(int a=b;a<=c;a++)
#define fb(a,b,c) for(int a=b;a>=1;a--)
using namespace std;
const int N=100000+10;
int n,m;
void Edge{
int nxt,to,w;
}e[N];
int dis[N],head[N],k;
void adde(int u,int v,int w){
e[++k].nxt=head[u];e[k].to=v;e[k].w=w;head[u]=k;
// 将已给数据转化为图,进行数据处理
}
bool vis[N];
queue<int> q; //定义队列
void spfa(int s){
memset(dis,0x7f,sizeof(dis)); //现将两点之间的距离先设为无限大
memset(vis,0,sizeof(vis)); //将起始点设为 0
dis[s]=0;q.push(s);vis[s]=true;
while(!q.empty()){ //当队列不为空时,不断的对压入队列中的每个元素进行松弛操作
int now=q.front();q.pop();vis[now]=false;
for(int i=head[now];i;i=e[i].nxt){
int to=e[i].to;
if(dis[to]>dis[now]+e[i].w){
dis[to]=dis[now]+e[i].w;
//判断是否进行松弛操作
if(!vis[to]) q.push(to),vis[to]=true;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,m){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
adde(u,v,w),adde(v,u,w); // 建图函数
}spfa(1);printf("%d",dis[n]);
}
输入案例如下
起始点 终点 权值 |
---|
a b 24 |
a c 8 |
a d 15 |
b e 6 |