SPFA:Shortest Path Faster Algoriithm 快速最短路径算法
SPFA的核心算法就是Bell-Ford算法。它使用一个队列或者一个栈来减少了Bell-Ford中不必要的松弛。可以处理负边和环的情况,他的使用比Dijstra更广泛。但是未经优化的SPFA算法时间复杂度不稳定,测试用例对它的影响较大。所以有的时候为了简单方便,我们直接使用Dijstra算法来解决。
SPFA实现的过程非常类似于BFS。他们都是使用队列来维护,不同的是,BFS的每个顶点只入队一次,而SPFA的结点则课能会入队多次。所以我们需要一个数组bool vis[] 来记录该顶点是否在队列中。SPFA实现过程如下:
步骤一: 首先将将源点s入队,将所有点到s的距离设置为dis[i]=∞,dis[s]=0
步骤二:如果队列为空,算法终止。否则取出队首元素u,将与u相连的边<u,v>进行松弛,如果dis[u]距离更新了且u不在队列中,则将u入队,若u进队次数大于n(总顶点数),则说明有负环,立即结束算法。
步骤三:不断地重复步骤二,直到算法结束
SPFA算法的时间复杂度取决于顶点总共的入队次数,他的算法时间复杂度为O(ke),e是边数,k是每个节点平均入队的次数,一般有k<2.
#include<queue> #define INF INT_MAX/2 #define MAX_SIZE 1000 int dis[MAX_SIZE]; //保存最短距离 bool vis[MAX_SIZE]; int a[MAX_SIZE][MAX_SIZE]; //邻接矩阵存储 int times[MAX_SIZE]; //记录顶点入队次数 bool SPFA(int s,int n) { int i,v; bool label = 1; //用来记录是否会出现环 memset(vis, 0, sizeof(vis)); memset(times, 0, sizeof(times)); queue<int>Q; //保存顶点的队列 for (i = 0; i <n; i++) dis[i] = INF; //初始化为无穷 dis[s] = 0; //源节点 Q.push(s); //源节点入队 vis[s] = 1; //源节点在队列中,所以标记为1 times[s]++; while (!Q.empty()){ //如果队列非空 v = Q.front(); //取出队列一个元素 Q.pop(); vis[v] = 0; //将该点标记为不在队列中 for (i = 0; i < n; i++) { //松弛该点的邻边 if (dis[i] > a[v][i] + dis[v]) { dis[i] = a[v][i] + dis[v]; //松弛一把更新距离 if (!vis[i]) { //如果被松弛的顶点i不在队列中 vis[i] = 1; //加入队列并标记 Q.push(i); if (times[++i] > n) { //入队次数加1次,如果入队次数超过n的话,表示有环 label = 0; break; } } } } if (!label) break; } return label; //若有环返回0,无环返回1 }
时间: 2024-11-25 06:37:12