SPFA算法O x

3、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即可。例题中的参考程序使用了循环队列。

样例:

7 12

1 2 24

1 3 8

1 4 15

2 5 6

3 5 7

3 6 3

4 7 4

5 7 9

6 7 3

6 4 5

6 5 2

7 2 3

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4
 5 using namespace std;
 6 const int Maxn=1001,Maxx=999999;
 7
 8 int que[Maxn],map[Maxn][Maxn],dis[Maxn];
 9 bool cun[Maxn];
10 int n,m;
11 int qianqu[Maxn],q[Maxn];
12
13 void SPFA(int s)
14 {
15     int head=0,tail=1,v;
16     que[1]=s;   //将s入队
17     dis[s]=0;    //s to s 的距离为0
18     qianqu[s]=s;  //记录下s的前趋
19     cun[s]=1;  //进行标记,已经入队
20     do
21     {
22         v=que[++head];  //取出队头元素
23         cun[v]=0; //将标记撤销,说明已经出队
24         for(int i=1;i<=n;i++)
25         {
26             if(dis[i]>dis[v]+map[v][i])  //进行松弛
27             {
28                 dis[i]=dis[v]+map[v][i];
29                 qianqu[i]=v;   //记录前趋
30                 if(!cun[i])   //如果队中没有i元素
31                 {
32                     que[++tail]=i;  //入队
33                     cun[i]=1;   //进行标记,已经入队
34                 }
35             }
36         }
37
38     }while(head<tail);   //进行循环的条件
39 }
40
41 void print(int s,int e)
42 {
43     int tot=1;
44     q[tot]=e;
45     tot++;
46     int temp=qianqu[e];
47     while(temp!=s)
48     {
49         q[tot]=temp;
50         tot++;
51         temp=qianqu[temp];
52     }
53     q[tot]=s;
54     for(int i=tot;i>=1;i--)
55     {
56         if(i!=1)
57           cout<<q[i]<<"-->";
58         else
59           cout<<q[i]<<endl;
60     }
61 }
62
63 int main()
64 {
65     memset(dis,Maxx,sizeof(dis));   //dis与map必须!!!进行初始化
66     memset(map,Maxx,sizeof(map));   //这样才能够松弛
67     scanf("%d %d",&n,&m);
68     int q,h,w,s,e;
69     for(int i=1;i<=m;i++)
70     {
71         scanf("%d %d %d",&q,&h,&w);
72         map[q][h]=w;
73     }
74     //memset(cun,0,sizeof(cun));
75     //memset(que,0,sizeof(que));
76     //这两个可以不用进行初始化
77     scanf("%d %d",&s,&e);
78     SPFA(s);
79     printf("%d\n",dis[e]);
80     print(s,e);
81     return 0;
82 }
时间: 2024-10-13 13:56:53

SPFA算法O x的相关文章

POJ 3259 Wormholes SPFA算法题解

本题其实也可以使用SPFA算法来求解的,不过就一个关键点,就是当某个顶点入列的次数超过所有顶点的总数的时候,就可以判断是有负环出现了. SPFA原来也是可以处理负环的. 不过SPFA这种处理负环的方法自然比一般的Bellman Ford算法要慢点了. #include <stdio.h> #include <string.h> #include <limits.h> const int MAX_N = 501; const int MAX_M = 2501; const

POJ 1847 Tram 【最短路,spfa算法,题意理解是关键呀!!】

Tram Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 13468   Accepted: 4954 Description Tram network in Zagreb consists of a number of intersections and rails connecting some of them. In every intersection there is a switch pointing to t

[知识点]SPFA算法

// 此博文为迁移而来,写于2015年4月9日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vx93.html 1.前言 最短路算法有很多种,类似于Floyd和Dijkstra都是很早之前就学了的.其实每种最短路算法有各自的优势.Floyd适合于跑完全图,但是效率太慢(O(n3)).Dijkstra适合于跑没有负权的图,效率为O(n2).而今天介绍的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

HDU 2112 HDU Today【最短路+map容器,spfa算法+Dijkstra算法】

HDU Today Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 25102    Accepted Submission(s): 6067 Problem Description 经过锦囊相助,海东集团终于度过了危机,从此,HDU的发展就一直顺风顺水,到了2050年,集团已经相当规模了,据说进入了钱江肉丝经济开发区500强.这时候

hihocoder1093最短路(SPFA算法)

算法描述: 首先将起始节点入队,然后每次从队列中取出一个节点,更新其邻接点的最短路径值,若有被更新,则检查该邻接点是否在队列中,若不在队列中,则入队.如此循环直到队空时算法结束. 当图中不存在负环时,算法一定会收敛,并能得到所求最短路.原因在于,每次从队列中取出一个节点并更新其邻接点的过程其实都是在向最优解逼近的过程,且只有当有更新的时候才可能向队列增加节点.由于不断的再向最优解逼近,所以到最后一定会达到最优解且不再有节点入队,队列最终为空,算法收敛.SPFA算法与dijkstra相比有一个好处

SPFA算法

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

Cocos2d-x 地图行走的实现2:SPFA算法

上一节<Cocos2d-x 地图行走的实现1:图论与Dijkstra算法> http://blog.csdn.net/stevenkylelee/article/details/38408253 本节实践另一种求最短路径算法:SPFA 1.寻路算法实现上的优化 上一节我们实现的Dijkstra用了一个哈希表来保存搜索到的路径树.如果能用直接的访问的方式,就不要用哈希表,因为直接访问的方式会比哈希表更快.我们修改一下图顶点的数据结构.如下: /* 图顶点 */ class Vertex { fr

最短路 spfa算法

问题描述 给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环).请你计算从1号点到其他点的最短路(顶点从1到n编号). 输入格式 第一行两个整数n, m. 接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边. 输出格式 共n-1行,第i行表示1号点到i+1号点的最短路. 样例输入 3 31 2 -12 3 -13 1 2 样例输出 -1-2 数据规模与约定 对于10%的数据,n = 2,m = 2. 对于30%的数据,n <= 5,m <= 10. 对

(最短路径算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理与介绍

这一篇博客以一些OJ上的题目为载体.整理一下最短路径算法.会陆续的更新... 一.多源最短路算法--floyd算法 floyd算法主要用于求随意两点间的最短路径.也成最短最短路径问题. 核心代码: /** *floyd算法 */ void floyd() { int i, j, k; for (k = 1; k <= n; ++k) {//遍历全部的中间点 for (i = 1; i <= n; ++i) {//遍历全部的起点 for (j = 1; j <= n; ++j) {//遍历