算法介绍:
- 求单源最短路
- 在Bellman-Ford算法基础上加队列优化,减少了冗余的松弛操作
- 松弛操作必定只会发生在最短路径前导节点上,用一个队列记录松弛过的节点,可以避免了冗余计算,将复杂度降低到0(kE)(注:一般k<=2,也可能很大)
算法过程:
- 建立一个队列,初始时队列里只有起始点;建立存储最短距离的数组,初始化为无穷大
- 用队列里的点松弛起始点到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空。
- 如果一个点入队次数超过N,那么图中有负环。
代码如下:
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <memory.h>
#define INF 0x3f3f3f3f
using namespace std;
const int NUM=1005;
struct Edge
{
int v;//相关边的终点
int cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
queue<int>q;
vector<Edge> E[NUM];//对每一个点开辟一个数组,存与它相关的点和对应权重
int n,m,counter=0;
bool visit[NUM];
int Dis[NUM];
int cnt[NUM];//每个点的入队次数,用来判定是否存在负环
void addege(int u,int v,int w)
{
E[u].push_back(Edge(v,w));
}
bool SPFA(int s)
{
memset(visit,false,sizeof(visit));
memset(cnt,0,sizeof(cnt));
while(!q.empty()) q.pop();
Dis[s]=0;
visit[s]=true;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i].v;
if(Dis[v]>Dis[u]+E[u][i].cost)
{
Dis[v]=Dis[u]+E[u][i].cost;
if(!visit[v])
{
q.push(v);
visit[v]=true;
if(++cnt[v]>n)
return false;
}
}
}
}
return true;
}
int main()
{
//输入顶点个数,边数,起点,终点
int s,e;
cin>>n>>m>>s>>e;
for(int i=1;i<=n;i++)
{
Dis[i]=INF;
}
Dis[s]=0;
for(int i=0;i<m;i++)
{
int u,v,w;
cin>>u>>v>>w;//起点终点权重
addege(u,v,w);
}
if(SPFA(s)==false)
cout<<"fail"<<endl;
else
cout<<Dis[e]<<endl;
return 0;
}