最短路——spfa
适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。 我们约定有向加权图G不存在负权回路,即最短路径一定存在。当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重点。
算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G。我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止
期望的时间复杂度O(ke), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2。
实现方法:
建立一个队列,初始时队列里只有起始点,再建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点作为起始点去刷新到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空。
判断有无负环:
如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)

首先建立起始点a到其余各点的
最短路径表格

首先源点a入队,当队列非空时:
1、队首元素(a)出队,对以a为起始点的所有边的终点依次进行松弛操作(此处有b,c,d三个点),此时路径表格状态为:

在松弛时三个点的最短路径估值变小了,而这些点队列中都没有出现,这些点
需要入队,此时,队列中新入队了三个结点b,c,d
队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e点),此时路径表格状态为:

在最短路径表中,e的最短路径估值也变小了,e在队列中不存在,因此e也要
入队,此时队列中的元素为c,d,e
队首元素c点出队,对以c为起始点的所有边的终点依次进行松弛操作(此处有e,f两个点),此时路径表格状态为:

在最短路径表中,e,f的最短路径估值变小了,e在队列中存在,f不存在。因此
e不用入队了,f要入队,此时队列中的元素为d,e,f
队首元素d点出队,对以d为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:

在最短路径表中,g的最短路径估值没有变小(松弛不成功),没有新结点入队,队列中元素为f,g
队首元素f点出队,对以f为起始点的所有边的终点依次进行松弛操作(此处有d,e,g三个点),此时路径表格状态为:

在最短路径表中,e,g的最短路径估值又变小,队列中无e点,e入队,队列中存在g这个点,g不用入队,此时队列中元素为g,e
队首元素g点出队,对以g为起始点的所有边的终点依次进行松弛操作(此处只有b点),此时路径表格状态为:

在最短路径表中,b的最短路径估值又变小,队列中无b点,b入队,此时队列中元素为e,b
队首元素e点出队,对以e为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:

在最短路径表中,g的最短路径估值没变化(松弛不成功),此时队列中元素为b
队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e这个点),此时路径表格状态为:

在最短路径表中,e的最短路径估值没变化(松弛不成功),此时队列为空了
最终a到g的最短路径为14
上面的一坨说白了就是:先拿一个点(起点)入队,然后那这个点与他相连的边进行更新最小值,若更新成功,把相连的点加入队列中,改点弹出,重复上诉操作,直到队列变成空。这是我们所要求的对短路都放在了dis数组里。
代码:
法一:(但是我不喜欢这种方式)
#include<cstdio>
using namespace std;
struct node
{int x;
int value;
int next;
};
node e[];
],dis[],st[],queue[];
int main()
{
int n,m,u,v,w,start,h,r,cur;
while(scanf("%d%d",&n,&m)!=EOF)
{
;i<=;i++)
{
visited[i]=;
dis[i]=-;
st[i]=-; //这个初始化给下边那个while循环带来影响
}
;i<=m;i++)
{
scanf("%d%d%d\n",&u,&v,&w);
e[i].x=v; //记录后继节点 相当于链表中的创建一个节点,并使得数据域先记录
e[i].value=w;
e[i].next=st[u]; //记录顶点节点的某一个边表节点的下标,相当于在链表中吧该边表节点的next指针先指向他的后继边表节点
st[u]=i; //把该顶点的指针指向边表节点,相当于链表中的插入中,头结点的指针改变
}
start=;
visited[start]=;
dis[start]=;
h=;
r=;
queue[r]=start;
while(h!=r)
{
h=(h+)%;
cur=queue[h];
int tmp=st[cur];
visited[cur]=;
)
{
if (dis[e[tmp].x]<dis[cur]+e[tmp].value) //改成大于号才对
{
dis[e[tmp].x]=dis[cur]+e[tmp].value;
)
{
visited[e[tmp].x]=;
r=(r+)%;
queue[r]=e[tmp].x;
}
}
tmp=e[tmp].next;
}
}
printf("%d\n",dis[n]);
}
;
}
法二:
#include<queue>
#include<cstdio>
#define INF 2147483647LL
using namespace std;
struct node {
int to,dis,next;
}edge[];
],dis[];//n 点的个数 m 连边的条数 s 起点 dis_1 储存最小边
inline void edge_add(int from,int to,int dis)
{
num++;
edge[num].to=to;
edge[num].dis=dis;
edge[num].next=head[from];
head[from]=num;
}
void SPFA(int start)
{
queue<int>que;
];
;i<=n;i++) dis[i]=INF,if_in_spfa[i]=false;//初始化
dis[start]=,if_in_spfa[start]=true;//加入第一个点(起点)
que.push(start);//将起点入队
while(!que.empty())//如果队列不为空,就接着执行操作,直到队列为空
{
int cur_1=que.front();//取出队列的头元素
que.pop();//将队列头元素弹出
for(int i=head[cur_1];i;i=edge[i].next)//枚举与该点连接的边
{
if(dis[cur_1]+edge[i].dis<dis[edge[i].to])//如果能更新最小值
{
dis[edge[i].to]=edge[i].dis+dis[cur_1];//更新最小值
if(!if_in_spfa[edge[i].to])//将所能更新的没入队的元素入队
{
if_in_spfa[edge[i].to]=true;//标记为已入队
que.push(edge[i].to);//推入队中
}
}
}
if_in_spfa[cur_1]=false;//将该点标记为出队列
}
}
int main()
{
int s;
scanf("%d%d%d",&n,&m,&s);
int from,to,dis;
;i<=m;i++)
{
scanf("%d%d%d",&from,&to,&dis);
edge_add(from,to,dis);//用邻接链表储存
}
SPFA(s);//从起点开始spfa
;i<=n;i++) printf("%d ",dis[i]);
;
}
最短路——spfa的更多相关文章
- 最短路模板(Dijkstra & Dijkstra算法+堆优化 & bellman_ford & 单源最短路SPFA)
关于几个的区别和联系:http://www.cnblogs.com/zswbky/p/5432353.html d.每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个(草儿家到 ...
- L - Subway(最短路spfa)
L - Subway(最短路spfa) You have just moved from a quiet Waterloo neighbourhood to a big, noisy city. In ...
- ACM/ICPC 之 最短路-SPFA+正逆邻接表(POJ1511(ZOJ2008))
求单源最短路到其余各点,然后返回源点的总最短路长,以构造邻接表的方法不同分为两种解法. POJ1511(ZOJ2008)-Invitation Cards 改变构造邻接表的方法后,分为两种解法 解法一 ...
- POJ 1847 Tram --set实现最短路SPFA
题意很好懂,但是不好下手.这里可以把每个点编个号(1-25),看做一个点,然后能够到达即为其两个点的编号之间有边,形成一幅图,然后求最短路的问题.并且pre数组记录前驱节点,print_path()方 ...
- 【POJ】3255 Roadblocks(次短路+spfa)
http://poj.org/problem?id=3255 同匈牙利游戏. 但是我发现了一个致命bug. 就是在匈牙利那篇,应该dis2单独if,而不是else if,因为dis2和dis1相对独立 ...
- 【wikioi】1269 匈牙利游戏(次短路+spfa)
http://www.wikioi.com/problem/1269/ 噗,想不到.. 次短路就是在松弛的时候做下手脚. 设d1为最短路,d2为次短路 有 d1[v]>d1[u]+w(u, v) ...
- POJ 1511 最短路spfa
题很简单 就是有向图中求给出的源点到其余所有点的最短路的和与其余所有点到源点的最短路之和 一开始以为dij对于正权图的单源最短路是最快的 写了一发邻接表的dij 结果超时 把所有的cin改成scanf ...
- Layout---poj3169(差分约束+最短路spfa)
题目链接:http://poj.org/problem?id=3169 有n头牛站成一排 在他们之间有一些牛的关系比较好,所以彼此之间的距离不超过一定距离:也有一些关系不好的牛,希望彼此之间的距离大于 ...
- LightOJ 1074 Extended Traffic (最短路spfa+标记负环点)
Extended Traffic 题目链接: http://acm.hust.edu.cn/vjudge/contest/122685#problem/O Description Dhaka city ...
- POJ 3835 & HDU 3268 Columbus’s bargain(最短路 Spfa)
题目链接: POJ:http://poj.org/problem?id=3835 HDU:http://acm.hdu.edu.cn/showproblem.php?pid=3268 Problem ...
随机推荐
- JAVA中反射机制六(java.lang.reflect包)
一.简介 java.lang.reflect包提供了用于获取类和对象的反射信息的类和接口.反射API允许对程序访问有关加载类的字段,方法和构造函数的信息进行编程访问.它允许在安全限制内使用反射的字段, ...
- windows安装zookeeper和kafka,flume
一.安装JDK 过程比较简单,这里不做说明. 最后打开cmd输入如下内容,表示安装成功 二.安装zooeleeper 下载安装包:http://zookeeper.apache.org/release ...
- MDI窗体简单方法(调用,闪屏)
调用方式: RibbonForm mdishow = new RibbonForm(); //实例化 midshow.MdiParent = this; //设置在主窗体,以MDI的方式显示,关键属性 ...
- 爬虫实战--使用Selenium模拟浏览器抓取淘宝商品美食信息
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exce ...
- Vue SPA 首屏加载优化实践
写在前面 本文记录笔者在Vue SPA项目首屏加载优化过程中遇到的一些坑及优化方案! 我们以 vue-cli 工具为例,使用 vue-router 搭建SPA应用,UI框架选用 element-ui ...
- php简单文件管理器——php经典实例
<html> <head> <title>文件管理</title> <meta charset='utf-8' /> </head&g ...
- 搭建linux+nginx+mysql+php环境
yum install -y gcc gcc-c++ make zlib zlib-devel pcre pcre-devel libjpeg libjpeg-devel libpng libpn ...
- xshell连接Ubuntu虚拟机
Ubuntu系统 1,安装ssh sudo apt-get install openssh-server 2,启动ssh进程 /etc/init.d/ssh start 3,查看进程信息 ps -e ...
- Django 1.10文档中文版Part4
2.10 高级教程:如何编写可重用的apps 2.10.1 重用的概念 The Python Package Index (PyPI)有大量的现成可用的Python库.https://www.djan ...
- Zabbix3.0源码安装
环境:nginx1.6.3 php-5.6.22 mysql-5.5.49 请参考前面的博文自行搭建 安装依赖并创建用户 [root@test88 ~]# yum install -y libxml2 ...