SPFA 最短路 带负权边的---- 粗了解
SPFA(Shortest Path Faster Algorithm)是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算。
算法大致流程是用一个队列来进行维护。 初始时将源加入队列。 每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。 直到队列为空时算法结束。
这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法
SPFA——Shortest Path Faster Algorithm,它可以在O(kE)的时间复杂度内求出源点到其他所有点的最短路径,可以处理负边。SPFA的实现甚至比Dijkstra或者Bellman_Ford还要简单
SPFA可以处理负权边
定理: 只要最短路径存在,上述SPFA算法必定能求出最小值。
证明:
每次将点放入队尾,都是经过松弛操作达到的。换言之,每次的优化将会有某个点v的最短路径估计值d[v]变小。所以算法的执行会使d越来越小。由于我们假定图中不存在负权回路,所以每个结点都有最短路径值。因此,算法不会无限执行下去,随着d值的逐渐变小,直到到达最短路径值时,算法结束,这时的最短路径估计值就是对应结点的最短路径值。
期望的时间复杂度O(ke), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2。
判断有无负环:
如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)
/*********************************************/
// d数组类似迪杰斯特拉的dis数组,记录起点到i点的局部最优解
// c数组用来记录访问 i 点的次数
// vis 记录是否在队列里面
// 用数组模拟邻接表存图,w数组为权值
/*********************************************/
bool spfa_bfs(int s) // s为图的起点
{
queue <int> q; // 队列里存点
memset(d,0x3f,sizeof(d));
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
q.push(s);
vis[s]=1;
c[s]=1;
d[s]=0;
//顶点入队vis要做标记,另外要统计顶点的入队次数
while(!q.empty())
{
int x;
x=q.front();
q.pop();
vis[x]=0;
//队头元素出队,并且消除标记
for(int k=f[x]; k!=0; k=nnext[k]) //遍历顶点x的邻接表
{
int y=v[k];
if( d[x]+w[k] < d[y]) //如果可以松弛
{
d[y]=d[x]+w[k]; //松弛
if(!vis[y]) //顶点y不在队内 不要重复入队列
{
vis[y]=1; //标记
c[y]++; //统计次数
q.push(y); //入队
if(c[y]>NN) //超过入队次数上限,说明有负环
return false;
}
}
}
}
return true;
}
给出一道题目,练练手.
本人AC代码: 仅供参考 ,不对的地方请指出
大致思路:
用数组模拟邻接表存图,然后直接套模板.
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdlib.h> using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MAX_SIZE=1005; int first[MAX_SIZE*2],nnext[MAX_SIZE*2];
int edge[MAX_SIZE*2][3],dist[MAX_SIZE],cnt[MAX_SIZE],vis[MAX_SIZE];
int V,E;
bool spfa_bfs(int start)
{
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
memset(dist,0xf3,sizeof(dist));
queue<int>q;
q.push(start);
vis[start]=1;
dist[start]=0;
while(!q.empty())
{
start=q.front();
q.pop();
vis[start]=0;
int k=first[start];
while(k!=-1)
{
int terminal=edge[k][1];
if(dist[terminal]<dist[start]+edge[k][2])
{
dist[terminal]=dist[start]+edge[k][2];
if(!vis[terminal])
{
q.push(terminal);
cnt[terminal]++;
vis[terminal]=1;
if(cnt[terminal]>V) return false;
}
}
k=nnext[k];
}
}
return true;
}
int main()
{
// printf("sb\n");
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
int i,j;
scanf("%d %d",&V,&E);
for(i=0; i<=1000; i++)
first[i]=-1;
for(i=0; i<E; i++)
{
int a,b,c,d,e,val1,val2;
scanf("%d %d %d %d %d",&a,&b,&c,&d,&e);
val1=d-c;
val2=e-c;
int xiaobiao=(i+1)*2-2;
edge[xiaobiao][0]=a,edge[xiaobiao][1]=b,edge[xiaobiao][2]=val1;
nnext[xiaobiao]=first[a];
first[a]=xiaobiao;
xiaobiao++;
edge[xiaobiao][0]=b,edge[xiaobiao][1]=a,edge[xiaobiao][2]=val2;
nnext[xiaobiao]=first[b];
first[b]=xiaobiao;
}
int ans=spfa_bfs(0);
// for(i=0;i<V;i++)
// printf("%d ",dist[i]);
// printf("\n"); if(!ans) printf("$$$\n");
else printf("%d\n",dist[V-1]);
}
return 0;
}
SPFA 最短路 带负权边的---- 粗了解的更多相关文章
- 图之单源Dijkstra算法、带负权值最短路径算法
1.图类基本组成 存储在邻接表中的基本项 /** * Represents an edge in the graph * */ class Edge implements Comparable< ...
- Expm 10_1 带负权值边的有向图中的最短路径问题
[问题描述] 对于一个带负权值边的有向图,实现Bellman-Ford算法,求出从指定顶点s到其余顶点的最短路径,并判断图中是否存在负环. package org.xiu68.exp.exp10; p ...
- hdu 6201 transaction (最短路变形——带负权最长路)
题意: 给定n个城市的货物买卖价格, 然后给定n-1条道路,每条路有不同的路费, 求出从某两个城市买卖一次的最大利润. 利润 = 卖价 - (买价 + 路费) 样例数据, 最近是从第一个点买入, 第4 ...
- SPFA 求带负权的单源最短路
int spfa_bfs(int s) { ///s表示起点. queue <int> q; memset(d,0x3f,sizeof(d)); ///d数组中存下的就是最短路径(存在的话 ...
- [板子]SPFA算法+链式前向星实现最短路及负权最短路
参考:https://blog.csdn.net/xunalove/article/details/70045815 有关SPFA的介绍就掠过了吧,不是很赞同一些博主说是国内某人最先提出来,Bellm ...
- Spfa 求含负权边的最短路 + 判断是否存在负权回路
在Bellman-Ford算法之后,我们总算迎来了spfa算法,其实就如同堆优化Dijkstra算法之于朴素版Dijkstra算法,spfa算法仅仅是对Bellman-Ford算法的一种优化,但是在形 ...
- POJ 3259 Wormholes 虫洞(负权最短路,负环)
题意: 给一个混合图,求判断是否有负环的存在,若有,输出YES,否则NO.有重边. 思路: 这是spfa的功能范围.一个点入队列超过n次就是有负环了.因为是混合图,所以当你跑一次spfa时发现没有负环 ...
- 【SPFA与Dijkstra的对比】CDOJ 1961 咸鱼睡觉觉【差分约束-负权最短路径SPFA】
差分约束系统,求最小值,跑最长路. 转自:https://www.cnblogs.com/ehanla/p/9134012.html 题解:设sum[x]为前x个咕咕中至少需要赶走的咕咕数,则sum[ ...
- Bellman-ford算法与SPFA算法思想详解及判负权环(负权回路)
我们先看一下负权环为什么这么特殊:在一个图中,只要一个多边结构不是负权环,那么重复经过此结构时就会导致代价不断增大.在多边结构中唯有负权环会导致重复经过时代价不断减小,故在一些最短路径算法中可能会凭借 ...
随机推荐
- 在 Windows 下用 TDM-GCC(MinGW)开发 DLL 涉及到数据同步锁及 DLL 初始化终止化函数的问题
在 Windows 下用 TDM-GCC(MinGW)开发 DLL 如果要用到数据同步锁,理论上可以采用 Windows API 提供的临界区实现(需要用到的函数有 InitializeCritica ...
- 记录一下 ps命令找出线程占用cpu情况
https://blog.csdn.net/xnn2s/article/details/11865339
- POJ 1991 Turning in Homework(区间DP)
题目链接 Turning in Homework 考虑区间DP $f[i][j][0]$为只考虑区间$[i, j]$且最后在$a[i]$位置交作业的答案. $f[i][j][1]$为只考虑区间$[i, ...
- codevs——2152 滑雪
2152 滑雪 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description trs喜欢滑雪.他来到了一个滑雪场,这个滑雪场 ...
- centos的python2.6.x升级到python2.7.x方法;python2.6.x的版本就不要用了
python2.6.x的版本,现在使用的很多插件都不支持了.所以如果你的centos还是使用的2.6.x版本,不要犹豫,赶紧升级到2.7.x版本 1.所谓升级,就是再安装一个python2.7.x版本 ...
- 具体解释window.history
Window.history保存用户在一个会话期间的站点訪问记录,用户每次訪问一个新的URL即创建一个新的历史记录. history.go().history.back().history.forwa ...
- Solidworks如何绘制标准螺纹线
1 绘制螺旋线,螺距为0.5mm,圈数为15,起始角度为0°. 2
- Cocos2d-x游戏《雷电大战》开源啦!要源代码要资源快快来~~
写在前面的话:这是笔者开发的第二个小游戏<雷电大战>,之前就过这个游戏和<赵云要格斗>一样,终于将会开源. 因为自己的一些个人原因. 这个游戏还没有完毕.可是很多网友都过来寻求 ...
- 分析Cocos2d-x横版ACT手游源码 1、公共
直接上代码 不说什么 这一款源码 凝视及多 PublicDef.h 公共头文件 #define NF_PLATFORM 1 //当前版本号(默觉得普通版) //版本号列表 #define NF_PLA ...
- Katalon
Katalon---一款好用的selenium自动化测试插件 selenium框架是目前使用较广泛的开源自动化框架,一款好的.基于界面的录制工具对于初学者来说可以快速入门:对于老手来说可以提高开发自动 ...