SPFA算法 O(kE)

主要思想是:

    初始时将起点加入队列。每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队。直到队列为空时算法结束。

    这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法。

SPFA 在形式上和广度优先搜索非常类似,不同的是广度优先搜索中一个点出了队列就不可能重新进入队列,但是SPFA中一个点可能在出队列之后再次被放入队列,也就是说一个点修改过其它的点之后,过了一段时间可能会获得更短的路径,于是再次用来修改其它的点,这样反复进行下去。

算法时间复杂度:O(kE)E是边数。K是常数,平均值为2

算法实现:

    dis[i]记录从起点si的最短路径,w[i][j]记录连接ij的边的长度。pre[v]记录前趋。

    team[1..n]为队列,头指针head,尾指针tail

    布尔数组exist[1..n]记录一个点是否现在存在在队列中。

    初始化:d[s]=0,d[v]=∞(vs),memset(exist,false,sizeof(exist));

    起点入队team[1]=s; head=0; tail=1;exist[s]=true;

    do

    {1、头指针向下移一位,取出指向的点u

    2、exist[u]=false;已被取出了队列

    3、foru相连的所有点v  //注意不要去枚举所有点,用数组模拟邻接表存储

       if (d[v]>d[u]+w[u][v])

         {   d[v]=d[u]+w[u][v];

             pre[v]=u;

             if (!exist[v]) //队列中不存在v点,v入队。

               {         //尾指针下移一位,v入队;

                    exist[v]=true;

                 }

          }

    }

    while (head < tail);

循环队列:

  采用循环队列能够降低队列大小,队列长度只需开到2*n+5即可。例题中的参考程序使用了循环队列。

完整代码:

 1 //spfa
 2
 3 #include<iostream>
 4 #include<cstdio>
 5 #include<cstring>
 6 using namespace std;
 7 const int maxn=0x7f;
 8 bool vis[1001];
 9 int map[1001][1001],dis[1001],queue[1001],path[1001];
10 int n,m,head=0,tail=1,now;
11
12
13 void spfa(int x)
14 {
15     queue[head]=x;
16     vis[x]=true;
17     dis[x]=0;
18     path[x]=x;
19     while(head<tail)
20     {
21         now=queue[head];
22         for(int i=1;i<=n;i++)
23         {
24             if(dis[i]>dis[now]+map[now][i])
25             {
26                 dis[i]=dis[now]+map[now][i];
27                 path[i]=now;
28                 if(vis[i]==false)
29                 {
30                     queue[tail++]=i;
31                     vis[i]=true;
32                 }
33             }
34         }
35     vis[now]=false;
36     head++;
37     }
38 }
39 void print(int st,int en)
40 {
41     int q[1001];
42     int tot=1;
43     q[tot]=en;
44     tot++;
45     int temp=path[en];
46     while(temp!=st)
47     {
48         q[tot]=temp;
49         tot++;
50         temp=path[temp];
51     }
52     q[tot]=st;
53     for(int i=tot;i>=1;i--)
54     {
55         if(i!=1)
56           printf("%d -- >",q[i]);
57         else
58           printf("%d",q[i]);
59     }
60     cout<<endl;
61 }
62 int main()
63 {
64     memset(map,maxn,sizeof(map));
65     scanf("%d%d",&n,&m);
66     int he,ta,len;
67     for(int i=1;i<=m;i++)
68     {
69         cin>>he>>ta>>len;
70         map[he][ta]=map[ta][he]=len;
71     }
72     memset(dis,maxn,sizeof(dis));
73     memset(vis,false,sizeof(vis));
74     memset(queue,0,sizeof(queue));
75     int start,end;
76     scanf("%d%d",&start,&end);
77     spfa(start);
78     printf("%d\n",dis[end]);
79     print(start,end);
80     return 0;
81 }
时间: 2024-10-11 07:48:08

SPFA算法 O(kE)的相关文章

SPFA算法O x

3.SPFA算法O(kE) 主要思想是:     初始时将起点加入队列.每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队.直到队列为空时算法结束.     这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法. SPFA 在形式上和广度优先搜索非常类似,不同的是广度优先搜索中一个点出了队列就不可能重新进入队列,但是SPFA中一个点可能在出队列之后再次被放入队列,也就是说一个点修改过其它的点之后,过了一段

spfa算法详解

program: #include<cstdio> using namespace std; struct node {int x; int value; int next; }; node e[60000]; int visited[1505],dis[1505],st[1505],queue[1000]; int main() { int n,m,u,v,w,start,h,r,cur; freopen("c.in","r",stdin); freo

SPFA算法

适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径一定存在.当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重点. 算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G.我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计

(转)SPFA算法

原文地址:http://www.cnblogs.com/scau20110726/archive/2012/11/18/2776124.html 粗略讲讲SPFA算法的原理,SPFA算法是1994年西安交通大学段凡丁提出 是一种求单源最短路的算法 算法中需要用到的主要变量 int n;  //表示n个点,从1到n标号 int s,t;  //s为源点,t为终点 int d[N];  //d[i]表示源点s到点i的最短路 int p[N];  //记录路径(或者说记录前驱) queue <int>

最短路径--SPFA 算法

适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径一定存在.当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重点. 算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G.我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计

SPFA 算法详解( 强大图解,不会都难!) (转)

适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便 派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径一定存在.当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重 点. 算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G.我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的 结点,优化时每次取出队首结点u,并且用u点当前的最短路

SPFA 算法详解

适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便 派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径一定存在.当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重 点. 算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G.我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的 结点,优化时每次取出队首结点u,并且用u点当前的最短路

转载:SPFA算法学习

转载地址:http://www.cnblogs.com/scau20110726/archive/2012/11/18/2776124.html 粗略讲讲SPFA算法的原理,SPFA算法是1994年西安交通大学段凡丁提出 是一种求单源最短路的算法 算法中需要用到的主要变量 int n;  //表示n个点,从1到n标号 int s,t;  //s为源点,t为终点 int d[N];  //d[i]表示源点s到点i的最短路 int p[N];  //记录路径(或者说记录前驱) queue <int>

最短路SPFA 算法详解

最短路SPFA 算法详解 适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径一定存在.当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重点. 算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G.我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并