图论-单源最短路-SPFA算法

有关概念:

  最短路问题:若在图中的每一条边都有对应的权值,求从一点到另一点之间权值和最小的路径

  SPFA算法的功能是求固定起点到图中其余各点的的最短路(单源最短路径)

  约定:图中不存在负权环,用邻接表存储有向图,di存放从起点到结点i的最短路,q为队列,保存待处理节点

思路:

  首先指定起点入队,取当前队头结点u,沿每一条与u相连的边向外扩展,对该边所指向的结点v松弛(比较当前dv与当前du加此边长,更新最短路值dv,以及最短路径prev)如果v不在队列中且更新了最短路值,v进队,直至队列中没有元素时终止

  较于Dijkstra,SPFA能处理带负权的边,但如果点进队的次数过多,时间效率就不如前者高

 1 #include<cstdio>
 2 #include<cstring>
 3 #define MAXN
 4 #define MAXM
 5 #define INF 214748364
 6 int n,m,cnt,d[MAXN],heads[MAXN],q[MAXN],pre[MAXN];
 7 int head,tail;//队头、队尾指针
 8 bool viss[MAXN];//结点i是否在队列中
 9 struct node
10 {
11     int u,v;
12     int next;
13     int val;
14 }edge[MAXM];
15 void add(int x,int y,int z)
16 {
17     edge[++cnt].u=x;
18     edge[cnt].v=y;
19     edge[cnt].next=heads[x];
20     edge[cnt].val=z;
21     heads[x]=cnt;
22 }
23 void SPFA()
24 {
25     head=1;tail=2;
26     q[1]=1;
27     viss[1]=1;//默认1为起点
28     while(head<tail)
29     {
30         for(int i=heads[q[head]];i!=0;i=edge[i].next)
31         {
32             if(d[q[head]]+edge[i].val<d[edge[i].v])
33             {
34                 d[edge[i].v]=d[q[head]]+edge[i].val;//松弛
35                 pre[edge[i].v]=i;//记录最短路径,pre存储边的序号
36                 if(!viss[edge[i].v])//如果v不在队列中,入队
37                 {
38                     q[tail++]=edge[i].v;
39                     viss[edge[i].v]=true;
40                 }
41             }
42         }
43         viss[q[head]]=false;
44         head++;//队头出队
45     }
46 }
47 void print(int x)
48 {
49     if(edge[x].u==1)
50     {
51         printf("%d %d ",1,edge[x].v);
52         return ;
53     }
54     print(pre[edge[x].u]);
55     printf("%d ",edge[x].v);
56 }
57 int main()
58 {
59     scanf("%d%d",&n,&m);
60     memset(heads,0,sizeof(heads));
61     for(int i=2;i<=n;i++)d[i]=INF;
62     int x,y,z;
63     for(int i=1;i<=m;i++)
64     {
65         scanf("%d%d%d",&x,&y,&z);
66         add(x,y,z);
67         add(y,x,z);//默认输入双向边,所以存储两条方向相反的边
68     }
69     SPFA();
70     printf("%d\n",d[n]);
71     x=pre[n];
72     print(x);//输出路径
73     return 0;
74 }

*参考:

http://baike.baidu.com/link?url=FxZ5Ces0YdAHMPmVyJG7f_wJ9-8c6EHreyuDEfHpXsldfk-rfj7ZjtSETKX5Jp14WW28sutbf5zcnLSBcmKzM9zaUVD1Sn9WCwsidDVUhPnSX__1ukG38VjR5g5-5NvK_fjovt-kZIJ1bC4HK1MaBa

时间: 2024-10-25 02:44:58

图论-单源最短路-SPFA算法的相关文章

uva 10099 The Tourist Guide(单源最短路/spfa/dijkstra)

题目: 链接:点击打开链接 题意: 思路: 代码: #include <iostream> #include <cstring> #include <cstdio> using namespace std; int map[101][101]; void floyd(int n) { for(int k=1; k<=n; k++) for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) map[i][j] = m

单源最短路 Bellman-Ford算法

单源最短路问题是固定一个起点s,求它到所有点的最短路的问题. Bellman-Ford算法可以用于边权为负的情况而不像Dijkstra只适用于边权为正的情况(有负圈返回错误),但是其效率比较低. 记从起点s出发到顶点i的最短距离为的d[i] 那么 d[i] = min(d[j]+(j->i)|其中j->i属于E) 如果给定的图是DAG 那么可以用拓扑序给顶点编号,并利用这一条递推公式计算出d(DP). 如果图中有圈,就无法依赖这样的顺序进行计算.这种情况初始d[s]=0 d[i]=INF 再不

HDU ACM 1535 Invitation Cards单点到多源最短路-&gt;SPFA算法

题意:有一个起始站点,从这里送n个学生去其余的n-1个站点邀请人们去CSS,然后再返回CSS,使得总的花费最小.注意每次只能送一个,返回时每次也只能送一个,而且每条路是单向的. 分析:这相当于一个有向图,我们只需两次调用SPFA算法即可,第一次求出初始站点(在这里是1)到其它所有站点的最小花费,然后相加:第二次将图反向建立,即所有的边反向,再求出初始站点(这里是1)到其它站点的最小费用,之后相加,第二步的图反向后按照第一次的求法就相当于从其它所有点到初始点的最小距离,因为算法只能求单点到多点而不

单源最短路Dijkstra算法——matlab实现

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 基本思想 通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算). 此外,引进两个集合S和U.S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离). 初始时,S中只有起点s:U中是除s之外的顶点,并且U中顶点的路径是"起点s

单源最短路Dijstra算法

Dijstra算法是寻找从某一顶点i出发到大其他顶点的最短路径.Distra算法的思想与Prim算法很像,它收录顶点的规则是按照路径长度递增的顺序收录的.设v0是源顶点,我们要寻找从v0出发到其他任意一点的最短路径.设已经求解的顶点(已经找到从v0出发到达该顶点最短路径的顶点)组成的集合是S={v0,v1,...vk};在收录下一个顶点v的时候要么是(v0,v),要么是(v0,vj,v);如果是后者,则一定有vj∈S,这一点很容易用反正法证明.Dijstra算法的时间复杂度是O(V^2),若是稀

单源最短路——Dijkstara算法

算法基本思想:每次找到离源点最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径. 1.将所有的顶点分为两个部分:已知最短路程的顶点集合P和未知最短路径的顶点集合Q 2.设置源点s到自己的最短路径为0,若存在有源点能够直接到达的顶点i则吧dis[i]设置为e[s][i].同时把所有其它不能直接到达的顶点的最短路径设置为∞ 3.在集合Q的所有顶点中选择一个离源点s最近的顶点u即dis[u]最小,加入到集合P.并考察所有以点u为起点地边,对每条边进行松弛操作. 4.重复第三

[hiho 23]单源最短路-Dijstra算法

题目描述 维护一个集合,集合中的元素与点u的最短距离已经确定,求出集合内元素所能到达的点到点u的距离,取最短的距离对应的点加入集合直到集合包含点v. 每次更新距离只与新加入集合的点有关. #include <stdio.h> #include <string.h> #include <algorithm> #define N 1005 unsigned w[N][N]; int main(){ memset(w, -1, sizeof(w)); int n, m, u,

单源最短路-dijkstra算法(未优化)

1 bool used[maxn]; 2 int g[maxn][maxn]; // 边未联系的填充为INF 3 int d[maxn]; 4 void dijkstra(int s){ 5 memset(g,false,sizeof(g)); 6 memset(d,INF,sizeof(d)); 7 d[s] = 0; 8 while(1){ 9 int v = -1; 10 for(int u = 0; u<v; u++){ 11 if(!used[u] && (v == -1|

模板C++ 03图论算法 1最短路之单源最短路(SPFA)

3.1最短路之单源最短路(SPFA) 松弛:常听人说松弛,一直不懂,后来明白其实就是更新某点到源点最短距离. 邻接表:表示与一个点联通的所有路. 如果从一个点沿着某条路径出发,又回到了自己,而且所经过的边上的权和小于0, 就说这条路是一个负权回路. 回归正题,SPFA是bellman-ford的一种改进算法,由1994年西安交通大学段凡丁提出.它无法处理带有负环的图,判断方法:如果某个点进入队列的次数超过N次则存在负环. SPFA的两种写法,bfs和dfs,bfs判别负环不稳定,相当于限深度搜索