码迷,mamicode.com
首页 > 编程语言 > 详细

[知识点]SPFA算法

时间:2015-07-26 23:52:46      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

// 此博文为迁移而来,写于2015年4月9日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vx93.html

 

1、前言
       最短路算法有很多种,类似于Floyd和Dijkstra都是很早之前就学了的。其实每种最短路算法有各自的优势。Floyd适合于跑完全图,但是效率太慢(O(n3))。Dijkstra适合于跑没有负权的图,效率为O(n2)。而今天介绍的SPFA算法,是有一位中国人——段凡丁所提出来的(其实我很想吐个槽。。为什么人家弗洛伊德大叔提出了算法就叫弗洛伊德算法,迪杰斯特拉大爷提出的东西就叫迪杰斯特拉算法,段凡丁提出来的算法就变成了什么鬼SPFA(Shortest Path Faster Algorithm)。。严重的歧视啊。。。)
       其实SPFA没什么要讲的。看了一下模板就瞬间懂了。
       
2、概念
       SPFA算法,是队列实现的Bellman-Ford算法。非常好理解,都知道BFS跑无权迷宫吧?其实SPFA可以直接理解为BFS跑有权图。因为它的形式和BFS太像了。大致流程是用一个队列来进行维护。 初始时将源加入队列。 每次从队列中取出一个元素,并对所有与他相邻的点进行松弛(松弛的意思自行脑补吧,看了程序就懂了),若某个相邻的点松弛成功,则将其入队。 直到队列为空时算法结束。先上代码:
-------------------------------------------------------------------------------------------------------------------
#include cstdio
#include cstring
#define INF 0x3f3f3f3f
#define MAXN 1005
 
struct Edge
{
       int v,next,val;
};
int n,m,u,v,val,h[MAXN],dist[MAXN],vis[MAXN],q[MAXN],tot;
Edge edge[MAXN];
 
void addEdge(int u,int v,int val)
{
       tot++;
       edge[tot].v=v;
       edge[tot].next=h[u];
       edge[tot].val=val;
       h[u]=tot;
}
 
void init()
{
       freopen("SPFA.in","r",stdin);
       freopen("SPFA.out","w",stdout);
       scanf("%d %d",&n,&m);
       for (int i=1;i<=m;i++)
       {
              scanf("%d %d %d",&u,&v,&val);
              addEdge(u,v,val); addEdge(v,u,val);
       }
}
 
void SPFA(int s)
{
       int head=1,tail=2;
       memset(dist,INF,sizeof(dist));
       memset(vis,0,sizeof(vis));
       memset(q,0,sizeof(q));
       dist[s]=0; vis[s]=1; q[1]=s;
       while (head!=tail)
       {
              int now=q[head];
              for (int x=h[now];x!=0;x=edge[x].next)
              {
                     if (dist[now]+edge[x].val《dist[edge[x].v])
                     {
                            dist[edge[x].v]=dist[now]+edge[x].val;
                            if (vis[edge[x].v]!=1)
                            {
                                   q[tail++]=edge[x].v;
                                   vis[edge[x].v]=1;
                            }
                     }
              }
              vis[now]=0;
              head++;
       }
       for (int i=2;i<=n;i++) printf("%d-->%d dist=%d\n",s,i,dist[i]);
}
 
int main()
{
       init();
       SPFA(1); // 1可以修改,表示源点
       return 0;
}
-------------------------------------------------------------------------------------------------------------------
 
       初始化:设dist[i]代表目前源点到i点的最短距离,开始时dist全部为INF(无穷大),只有Dist[s]=0。
       SPFA:维护一个队列,里面存放所有需要进行迭代的点。初始时队列中只有一个点s。用一个vis[i]记录i点是否处在队列中。每次迭代,取出队头的点v,依次枚举从v出发的边v->u,设边的长度为len,判断dist[v]+len是否小于dist[u],若小于则改进dist[u],并且由于s到u的最短距离变小了,有可能u可以改进其它的点,所以若u不在队列中,就将它放入队尾。这样一直迭代下去直到队列变空,也就是s到所有点的最短距离都确定下来,结束算法。
       备注:SPFA还有一个很强大的功能,可以判负权环。若一个点入队次数超过n,则有负权环。

[知识点]SPFA算法

标签:

原文地址:http://www.cnblogs.com/jinkun113/p/4678909.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!