SPFA是目前相当优秀的求最短路径的算法,值得我们掌握。
SPFA对Bellman-Ford算法优化的关键之处在于意识到:只有那些在前一遍松弛中改变了距离估计值的点,才可能引
起他们的邻接点的距离估计值的改变。因此,用一个先进先出的队列来存放被成功松弛的顶点。初始时,源点s入队。
当队列不为空时,取出对首顶点,对它的邻接点进行松弛。如果某个邻接点松弛成功,且该邻接点不在队列中,则将其
入队。经过有限次的松弛操作后,队列将为空,算法结束。SPFA算法的实现,需要用到一个先进先出的队列 queue 和
一个指示顶点是否在队列中的 标记数组 mark。为了方便查找某个顶点的邻接点,图采用临界表存储。
需要注意的是:仅当图不存在负权回路时,SPFA能正常工作。如果图存在负权回路,由于负权回路上的顶点无法收
敛,总有顶点在入队和出队往返,队列无法为空,这种情况下SPFA无法正常结束。
判断负权回路的方案很多,世间流传最广的是记录每个结点进队次数,超过|V|次表示有负权
关于SPFA的时间复杂度,一般认为是 O(kE),k一般为2。
如果在判断是否存在负权回路,推荐使用第一种优化形式,否则推荐使用SPFA。
//题目要求:判断有无负权环
#include <iostream>
using namespace std;
const int N = 502;
const int MAX = INT_MAX;
int f;
int n; //节点个数为n,边数为2*m+w
int m;
int w;
int queue[N],time[N],dis[N]; //循环队列,记录每个节点入队列的次数(大于n表示有负权环),dis记录最短路径值
bool vis[N]; //true表示在队列中。被松弛的点若在队列中,就不加入队列,出队列后值为false
int pre[N]; //节点i发出若干条边,pre[i]表示节点i当前正在遍历的边的前一条边的序号
typedef struct
{
int to;
int w;
int next;
}Edge;
Edge e[5201];
bool spfa()
{
int i,j,now,adj;
memset(vis,false,sizeof(vis));
memset(time,0,sizeof(time));
for(i = 2, dis[1] = 0; i <= n; i++)
dis[i] = MAX;
queue[0] = 1;
vis[1] = true;
time[1] = 1;
int head = 0,tail = 1;
while(head != tail)
{
now = queue[head];
head = (head + 1) % n;
vis[now] = false;
for(i = pre[now]; i != -1; i = e[i].next)
{
adj = e[i].to;
if(dis[now] != MAX && dis[now] + e[i].w < dis[adj])
{
if(adj == 1) //若初始点1本身包含负环,直接返回
return true;
dis[adj] = dis[now] + e[i].w;
if(!vis[adj])
{
queue[tail] = adj;
tail = (tail + 1) % n;
vis[adj] = true;
time[adj] ++;
if(time[adj] > n)
return true;
}
}
}
}
return false;
}
int main()
{
int i,j,edgeNum;
int from,to,w1;
cin>>f;
for(i = 0; i < f; i++)
{
edgeNum = 0;
memset(pre,-1,sizeof(pre));
memset(e,0,sizeof(e));
cin>>n>>m>>w;
for(j = 1; j <= m; j++)
{
cin>>from>>to>>w1;
e[edgeNum].to = to; e[edgeNum].w = w1; e[edgeNum].next = pre[from];
pre[from] = edgeNum;
edgeNum++;
e[edgeNum].to = from; e[edgeNum].w = w1; e[edgeNum].next = pre[to];
pre[to] = edgeNum;
edgeNum++;
}
for(j = 1; j <= w; j++)
{
cin>>from>>to>>w1;
e[edgeNum].to = to; e[edgeNum].w = -w1; e[edgeNum].next = pre[from];
pre[from] = edgeNum;
edgeNum++;
}
if(spfa())
cout<<"YES\n";
else
cout<<"NO\n";
}
return 0;
}
参见poj3259,1511
分享到:
相关推荐
求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm。 从名字我们就可以看出,这种算法在效率上一定有过人之处。
最短路SPFA算法。SPFA(Shortest Path Faster Algorithm)算法是求单源最短路径的一种算法,它是Bellman-ford的队列优化,它是一种十分高效的最短路算法。存在负权边时使用。
求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm。 这个是自己写的,思想还是一样发的。
dijstra单源最短路+详细注释,类似宽搜
求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm。 SPFA算法是西南交通大学段凡丁于1994年发表的. 从名字我们就可以看出,这种算法在效率上一定有过人之处。 很多时候,给定的图存在负权边,这时...
算法与数据结构课程设计(排序重构、单源最短路、拓扑排序)(csdn)————程序
单源最短路径的c语言源代码,在VC++6.0和turbo C上都能正确运行,配有实验截图
算法上机代码 包含Bellman-Floyd、 Kruskal 、Prim算法、单源最短路算法(Dijkstra)、多段图算法、多源最短路(Floyd)、改进的作业排序
最短路模板 by 程序猿小周 时间复杂度:O(n^3) 适用于:求单源最短路
单源最短路径——算法 单源最短路径——算法 单源最短路径——算法
使用C++实现的Queue improved Bellman-Ford单源最短路算法,在国内还被叫做SPFA。这个程序输入一个图,找到图中的一个点,这个点到最远点的长度最短。图使用邻接表保存。
典型的解决单源最短路径的贪心算法Dijkstra算法 可以运行
单源是指一个出发顶点,单源最短路问题指的是该顶点至所有可达顶点的最短路径问题。这是单源最短路问题的一个实例
Shortest path faster algorithm(SPFA) 1.6.2.1.2. 应用Applications 1.6.2.1.2.1. 差分约束系统 System of difference constraints 1.6.2.1.2.2. 有向无环图上的最短路 Shortest paths in DAG 1.6.2.2. 所有顶点对...
1.6.2.1.1.2.1. Shortest path faster algorithm(SPFA) 1.6.2.1.2. 应用Applications 1.6.2.1.2.1. 差分约束系统 System of difference constraints 1.6.2.1.2.2. 有向无环图上的最短路 Shortest paths in DAG 1.6....
校园导航 C语言程序设计 利用迪杰斯特拉求单源最短路算法,设计出的校园导航,求出学校一个景点到另一个景点的最短距离及路线。
cpp代码-dijkstra单源最短路
单源最短路径C语言实现,简单易懂,适合算法学习