spfa算法

2019 ICPC南京网络赛 H题(SPFA/Bellman-Ford)

匿名 (未验证) 提交于 2019-12-02 23:57:01
题意 给定六条边,让你设定他们的权值,加进去后,图不要产生负环。 输出六条边的边权。 ˼· 对于第一条边,u v,我求v到u的最短路dis,那么u v的边权即为dis。 将u v这条边加入图中。 对于第二条边,重复上述操作即可。 这样就能保证图中不会产生负环。 不能用 Dijkstra 算法,虽然没有负环,但是有负边就不能用 Dijkstra 用 SPFA 或者 Bellman - Ford 才能处理负边。 代码 # include < bits / stdc ++. h > using namespace std ; typedef long long ll ; const int maxn = 3e2 + 10 ; const int INF = 0x3f3f3f3f ; struct Edge { int v , cost ; Edge ( int _v = 0 , int _cost = 0 ) : v ( _v ) , cost ( _cost ) { } } ; vector < Edge > E [ maxn ] ; bool vis [ maxn ] ; int dist [ maxn ] ; int cnt [ maxn ] ; bool SPFA ( int n , int start ) { memset ( vis , false , sizeof (

spfa算法求最短路

匿名 (未验证) 提交于 2019-12-02 23:49:02
请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出impossible。 数据保证不存在负权回路。 输入格式 第一行包含整数n和m。 接下来m行每行包含三个整数x,y,z,表示点x和点y之间存在一条有向边,边长为z。 输出格式 输出一个整数,表示1号点到n号点的最短距离。 如果路径不存在,则输出”impossible”。 数据范围 1 ≤ n , m ≤ 10 5 1≤n,m≤105, 图中涉及边长绝对值均不超过10000。 输入样例: 3 3 1 2 5 2 3 -3 1 3 4 输出样例: 2 #include<iostream> #include<algorithm> #include<queue> #include<cstring> using namespace std; const int N=100010; int h[N],e[N],ne[N],w[N],dis[N],idx,n,m; bool st[N]; queue<int>q; void add(int a, int b, int c){ e[idx]=b;ne[idx]=h[a],w[idx]=c,h[a]=idx++; } int spfa(){ memset(dis,0x3f,sizeof(dis)); dis[1]=0; q.push(1); st[1]=true; while(q

SPFA

╄→гoц情女王★ 提交于 2019-12-02 12:22:25
原创建时间:2017-12-30 21:05:19 简单的SPFA最短路模板,适用于图的边权有负数的情况。 算法实现: 我们用数组d记录每个结点的最短路径估计值,而且用邻接表来存储图G。运用动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行操作,直至队列空为止。 代码实现: 给一个指针实现 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; #define MAXN 2500 + 5 #define DEBUG(x) cerr << #x << '=' << x const int Inf = 2e31-1; struct Node; struct Edge; struct Node{ Edge *firstEdge; int dist; bool inQueue; } node[MAXN]; struct Edge{ Node *s,*t; int w; Edge *next; Edge(Node *s

SPFA

最后都变了- 提交于 2019-12-02 06:57:28
这是求带负边权但是不能有负环的最短路算法,是中国人发明的一种算法吧也是。 首先我们还是用前向星存图,dis[]存当前的最短路径,然后用队列存储待优化的点。首先将起点入队,其次去遍历他所连接的点,如果可以松弛那么只要当前不在队里就将其入队。每一次去用他的队首去去遍历就可以,当队列为空的时候结束。 代码 #include<iostream> #include<cstdio> #include<queue> #define INF 2147483647 #define maxn 10005 #define maxm 500005 using namespace std; int m,n,s; int dis[maxn],head[maxn],vis[maxn]; struct edge{ int next; int w; int v; }e[maxm]; int tot=0; void add(int u,int v,int w){ e[++tot].next=head[u]; head[u]=tot; e[tot].w=w; e[tot].v=v; } queue <int>q; void spfa(){ for(int i=1;i<=n;i++) { dis[i]=INF; vis[i]=0; } q.push(s); dis[s]=0; vis[s]=1; while(!q

POJ - 1860 - Currency Exchange = SPFA

泄露秘密 提交于 2019-12-02 00:25:40
http://poj.org/problem?id=1860 题意:有n种货币,m个相互兑换关系,初始拥有货币s共v元,求是否可以财富增加。 题意并不是说要走简单路径,他只是说了简单路径这个东西。 这个题暴露了对SPFA的认识不够。 首先这个SPFA是没有带优化的,玄学算法不需要优化。 一般的SPFA是节点入队次数超过n次就认为它存在负环,但是这里并不是这样判断,存在负环并不代表一定可以兑换回s(说不定在负环里只有0的汇率换回来s,导致白搞)但是这又是怎么阻止算法死循环的呢? #include<algorithm> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<map> #include<set> #include<stack> #include<string> #include<queue> #include<vector> using namespace std; typedef long long ll; const int MAXN = 105; const int MAXM = 1005; int top; int head[MAXN]; struct Edge { int v, nxt; double w1, w2; } edge[MAXM]; void

SPFA判负环

送分小仙女□ 提交于 2019-12-01 16:53:55
目录 SPFA判负环 【前言】 【不可代替性】 【具体实现】 SPFA的过程 判负环 【核心代码】 【例题】 SPFA判负环 【前言】 最短路的求法中 最广为人知的 我仅仅知道的,有弗洛伊德,dijkstra和SPFA。 弗洛伊德最简单的三重循环,复杂度n^3,一般也就做个n小的题目,遇到n大一点的(超过1000)几乎就只能拿部分分。 SPFA是一种广为人知的已经死掉的算法(某人说过一道图论题如果不卡卡SPFA就不是一道好的图论题目),但是他却有一个很重要的作用,是其他三者无法代替的,那就是这篇博客的题目,判负环! dijkstra是这三种里面最为稳定的一种算法,何为稳定,弗洛伊德只能跑那么小的数据范围就可以看出来,在很多题目上面只能打一下暴力,SPFA就更不用多说了 他死了 ,所以dijkstra理所当然的成为了最稳定的算法。 说这么多就是为了引出SPFA判负环! 【不可代替性】 dijkstra和弗洛伊德都是判断不了负环的 弗洛伊德就是那么个枚举中间点的方法 根本不知道到底有没有负环 就那样求出来了一个最终结果 如果有负环那结果可能会是错误的 dijkstra遇到负权边就死了 更别说负环了 但是SPFA可以判断负环 具体原因不多赘述了,学过dijkstra和弗洛伊德的应该都知道 但是我不知道 【具体实现】 SPFA的过程 每次都拿一个点到起点的距离来松弛其他的点到起点的距离

POJ 1860 汇率 SPFA

泪湿孤枕 提交于 2019-12-01 05:28:07
题意 有多种汇币,汇币之间可以交换,这需要手续费,当你用100A币交换B币时,A到B的汇率是29.75,手续费是0.39,那么你可以得到(100 - 0.39) * 29.75 = 2963.3975 B币。问s币的金额经过交换最终得到的s币金额数能否增加 货币的交换是可以重复多次的,所以我们需要找出是否存在正权回路,且最后得到的s金额是增加的 怎么找正权回路呢?(正权回路:在这一回路上,顶点的权值能不断增加即能一直进行松弛) Sample Input 3 2 1 20.0 1 2 1.00 1.00 1.00 1.00 2 3 1.10 1.00 1.10 1.00 Sample Output YES 对SPFA算法进行改造,原来的dis改为存的货币的数量,改为求最长路,如果有自环,那么dis会不断增加没有上限 if(money[v]<(money[u]-E[u][i].fee)*E[u][i].rate){ money[v]=(money[u]-E[u][i].fee)*E[u][i].rate; if(!vis[v]) #define _CRT_SBCURE_NO_DEPRECATE #include <set> #include <map> #include <cmath> #include <queue> #include <bitset> #include <stack

SPFA算法

蹲街弑〆低调 提交于 2019-11-30 14:30:09
定义 SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。 原理 动态逼近法: ① 设立一个队列用来保存待优化的结点。 ② 优化时每次取出队首结点 u,并且用 u 点当前的最短路径估计值对 u 点所指向的结点 v 进行松弛操作,如果 v 点的最短路径估计值有所调整,且 v 点不在当前的队列中,就将 v 点放入队尾。 ③ 这样不断从队列中取出结点来进行松弛操作,直至队列空为止。 如果某个点进入队列的次数超过 N 次则存在负环。 松弛操作利用三角不等式:“三角形两边之和大于第三边”。 所谓对结点 i, j 进行松弛,就是判定是否 dis[j] > dis[i] + w[i,j],如果该式成立,则 dis[j] = dis[i] + w[i,j],反之不变。 简单地说,如果一个点的最短路被更新了,那么需要判断与此点连接的其他点是否也需要更新。 实现 代码 #include<bits/stdc++.h> using namespace std; const int maxn=1005; const int inf=0x3f3f3f3f; struct node { int v,w; node(){} node(int a,int b) {v=a;w=b;} }; int n,m; vector<node> e[maxn];

SPFA算法 (Shortest Path Faster Algorithm)

徘徊边缘 提交于 2019-11-30 08:50:10
SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE)。 简述原理 对于当前的一个点 i ,遍历与他直接相连的每一个顶点 j ,如果从 源点 到 j 的“最短”距离(之前记录的)大于从 源点 经由 i 再到 j 的距离,用后者更新前者( 松弛 ),并且记录路径。从 源点 作为当前点开始,依次按上述方法遍历每一个连通点,最后得到的便是 源点 到 其他所有点 的最短距离 示例 下面是一个无向图的示例程序 # include <cstdio> # include <queue> # include <iostream> using namespace std ; const int MAXN = 100 + 10 ; const int INF = 0x7fffffff ; static int sq [ MAXN ] [ MAXN ] ; int pre [ MAXN ] ; void path ( int x ) { if ( pre [ x ] != x ) path ( pre [ x ] ) ; printf ( "%d -> " , x ) ; } int * SPFA ( int n , int ori , int sq [ ] [

差分约束 + spfa + 最长路 [NOI1999] 01串

こ雲淡風輕ζ 提交于 2019-11-28 07:31:02
https://blog.csdn.net/Bill_Yang_2016/article/details/53556021 题目描述   给定7个整数N,A0,B0,L0,A1,B1,L1,要求设计一个01串S=s1s2…si…sN,满足:   1.si=0或si=1,1<=i<=N;   2.对于S的任何连续的长度为L0的子串sjsj+1…sj+L0-1(1<=j<=N-L0+1),0的个数大于等于A0且小于等于B0;   3.对于S的任何连续的长度为L1的子串sjsj+1…sj+L1-1(1<=j<=N-L1+1),1的个数大于等于A1且小于等于B1;   例如,N=6,A0=1,B0=2,L0=3,A1=1,B1=1,L1=2,则存在一个满足上述所有条件的01串S=010101。 用 S 表示01序列的1的个数的前缀和,然后就可以利用题目所给的不等式以及前缀和本身存在的信息,写出不等式进行差分约束算法。 注意!用前缀和表示区间和的时候所使用的前缀和数组的 L 要减1 。 #include <bits/stdc++.h> using namespace std; const int maxn = 1e5+110; int n,a0,b0,l0,a1,b1,l1; int s[maxn]; int cnt; struct node{ int from,to,val,next;