SPFA
是Bellman-Ford的队列优化,时效性相对好,时间复杂度O(kE)。
与Bellman-ford算法类似,SPFA算法采用一系列的松弛操作以得到从某一个节点出发到达图中其它所有节点的最短路径。所不同的是,SPFA算法通过维护一个队列,使得一个节点的当前最短路径被更新之后没有必要立刻去更新其他的节点,从而大大减少了重复的操作次数。
SPFA算法可以用于存在负数边权的图,这与dijkstra算法是不同的。
与Dijkstra算法与Bellman-ford算法都不同,SPFA的算法时间效率是不稳定的,即它对于不同的图所需要的时间有很大的差别。
在最好情形下,每一个节点都只入队一次,则算法实际上变为广度优先遍历,其时间复杂度仅为O(E)。另一方面,存在这样的例子,使得每一个节点都被入队(V-1)次,此时算法退化为Bellman-ford算法,其时间复杂度为O(VE)。
SPFA算法在负边权图上可以完全取代Bellman-ford算法,另外在稀疏图中也表现良好。但是在非负边权图中,为了避免最坏情况的出现,通常使用效率更加稳定的Dijkstra算法,以及它的使用堆优化的版本。通常的SPFA
http://blog.chinaunix.net/uid-26425645-id-3291898.html
很多时候,给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。SPFA的复杂度大约是O(kE),k是每个点的平均进队次数(一般的,k是一个常数,在稀疏图中小于2)。
实现方法:建立一个队列,初始时队列里只有起始点,在建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点去刷新起始点到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空。
此外,SPFA算法还可以判断图中是否有负权环,即一个点入队次数超过N。
http://www.cnblogs.com/shadowland/p/5870640.html
具体用邻接表怎么存储,看关于 BELLMAN算法的介绍。
#include<stdio.h>
#include<malloc.h>
struct node{
int flag;
int wight;
struct node* p;
};
struct shuzhu{
int d;
int f;
struct node* p;
};
void INITIALIZE_SOURCE(struct shuzhu*a,int n);
void SPFA(struct shuzhu* a,int n);
int main()
{
int n=0,m=0;
int u=0,v=0,l=0;
int i=0,j=0;
struct node* pp=0;
scanf("%d%d",&n,&m);
struct shuzhu a[n+1];
//初始化 邻接表
INITIALIZE_SOURCE(a,n);
//存储输入数据到链接表中
for(i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&l);
pp=(struct node*)malloc(sizeof(struct node)*1);
pp->flag=v;
pp->wight=l;
pp->p=a[u].p;
a[u].p=pp;
}
/*
//检验存储代码的正确性
for(i=1;i<=m;i++)
{
printf("[%d %d] ",a[i].d,a[i].f);
pp=a[i].p;
for(;pp!=NULL;)
{
printf("[%d %d] ",pp->flag,pp->wight);
pp=pp->p;
}
printf("\n");
}
*/
//SPFA算法,计算 1号点到其他点的最短路
SPFA(a,n);
//打印结果
for(i=2;i<=n;i++)
{
printf("%d\n",a[i].d);
}
return 0;
}
void INITIALIZE_SOURCE(struct shuzhu* a,int n)
{
int i=1;
a[1].d=0;
a[1].f=0;
a[1].p=NULL;
for(i=2;i<=n;i++)
{
a[i].d=10000000;
a[i].f=-1;
a[i].p=NULL;
}
return;
}
void SPFA(struct shuzhu* a,int n)
{
int i=-1;
int j=0;
struct node* q=0;
int Q[200000]={0};
Q[0]=1;
j=j+1;
while(i+1 != j)//队列为空
{
q=a[Q[i+1]].p;//Q出一个数 ,出队列
i=i+1;
while(q!=NULL)//遍历a[Q[i]]那一条链表
{
if(a[q->flag].d > a[Q[i]].d + q->wight)//要继续松弛操作,更新数据
{
a[q->flag].f=j;
a[q->flag].d=a[Q[i]].d+q->wight;
Q[j]=q->flag;//Q进入一个数(刚刚更新的点),入队列
j=j+1;
}
q=q->p;
}
}
return;
}