【定义与概念】

给定一张有向图,若其中存在一个环的所有权值之和为负数,这个环称为负环。

【算法实现】

当然,负环的求解可以暴搜,但是时间复杂度就难以入眼了,我们回到求解单源最短路径算法上面,看看它们能否求解。

我们知道

各种最短路算法
算法名称 能否处理负边 时间复杂度
Dijkstra 不能,负权的存在使得最短路径不一定最短 O(n^2)
堆优化Dijkstra 不能,如上 O(mlogn)
Bellman-Ford O(nm)
SPFA O(km)

我们主要使用SPFA,讲一下SPFA判断负环。

SPFA有三种以上的方法判断负环:

  1. 设cnt[x]表示1~x的最短路径包含边数,cnt[1]=0。当收敛边权(判断三角形不等式)时,更新cnt[y]=cnt[x]+1。如果某时cnt[x]>=边的总数m,说明存在负环。
  2. 记录每个点入队的次数,如果某个点入队次数超过点的总数n,说明存在最小环。
  3. 卡时判负环,判负环最骚的操作。给队列总长度做限制,超过限制说明有环。至于这个限制具体是什么,请去问玄学,我不知道。

给出第一、二种解法的参考吧。

拿道板子题出来。

P3385 【模板】负环

注意这道题鬼畜的输出。。。

这是第一种: 573ms /  5.04MB AC

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cmath>
  4. #include<queue>
  5. #include<algorithm>
  6. #include<cstring>
  7. #include<vector>
  8. #include<ctime>
  9. #define N 10010
  10. using namespace std;
  11. priority_queue<int,vector<int>,greater<int> > q;
  12. int head[N],tot,n,m,d[N],cnt[N];
  13. struct rec{
  14. int next,ver,edge;
  15. }g[N<<];
  16. void add(int x,int y,int val){
  17. g[++tot].ver=y,g[tot].edge=val;
  18. g[tot].next=head[x],head[x]=tot;
  19. }
  20. bool spfa(int x)
  21. {
  22. memset(d,0x3f,sizeof(d));
  23. memset(cnt,,sizeof(cnt));
  24. d[x]=;cnt[x]=;
  25. q.push(x);
  26. while(q.size())
  27. {
  28. int index=q.top();q.pop();
  29. for(int i=head[index];i;i=g[i].next){
  30. int y=g[i].ver,z=g[i].edge;
  31. if(d[y]>d[index]+z){
  32. d[y]=d[index]+z;
  33. cnt[y]=cnt[index]+;
  34. if(cnt[y]>=m) return ;
  35. q.push(y);
  36. }
  37. }
  38. }
  39. return ;
  40. }
  41. int main()
  42. {
  43. int t;
  44. cin>>t;
  45. while(t--)
  46. {
  47. memset(g,,sizeof(g));
  48. memset(head,,sizeof(head));
  49. if(!q.empty()) q.pop();
  50. tot=;
  51. scanf("%d%d",&n,&m);
  52. for(int i=;i<=m;i++){
  53. int x,y,val;
  54. scanf("%d%d%d",&x,&y,&val);
  55. if(val<) add(x,y,val);
  56. else add(x,y,val),add(y,x,val);
  57. }
  58. if(spfa()) cout<<"YE5"<<endl;
  59. else cout<<"N0"<<endl;
  60. }
  61. return ;
  62. }

这是第二种:1965ms /  9.04MB 91pnts

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cmath>
  4. #include<queue>
  5. #include<algorithm>
  6. #include<cstring>
  7. #include<vector>
  8. #define N 10010
  9. using namespace std;
  10. priority_queue<int,vector<int>,greater<int> > q;
  11. int head[N],tot,n,m,d[N],cnt[N];
  12. struct rec{
  13. int next,ver,edge;
  14. }g[N<<];
  15. void add(int x,int y,int val){
  16. g[++tot].ver=y,g[tot].edge=val;
  17. g[tot].next=head[x],head[x]=tot;
  18. }
  19. bool spfa(int x)
  20. {
  21. memset(v,,sizeof(v));
  22. memset(d,0x3f,sizeof(d));
  23. memset(cnt,,sizeof(cnt));
  24. d[x]=;cnt[x]=;
  25. q.push(x);
  26. while(q.size())
  27. {
  28. int index=q.top();q.pop();
  29. for(int i=head[index];i;i=g[i].next){
  30. int y=g[i].ver,z=g[i].edge;
  31. if(d[y]>d[index]+z){
  32. d[y]=d[index]+z;
  33. if(cnt[y]>=n) return ;
  34. cnt[y]++,q.push(y),v[y]=;
  35. }
  36. }
  37. }
  38. return ;
  39. }
  40. int main()
  41. {
  42. int t;
  43. cin>>t;
  44. while(t--)
  45. {
  46. memset(g,,sizeof(g));
  47. memset(head,,sizeof(head));
  48. if(!q.empty()) q.pop();
  49. tot=;
  50. scanf("%d%d",&n,&m);
  51. for(int i=;i<=m;i++){
  52. int x,y,val;
  53. scanf("%d%d%d",&x,&y,&val);
  54. if(val<) add(x,y,val);
  55. else add(x,y,val),add(y,x,val);
  56. }
  57. if(spfa()) cout<<"YE5"<<endl;
  58. else cout<<"N0"<<endl;
  59. }
  60. return ;
  61. }

【原创】SPFA判负环的更多相关文章

  1. POJ 3259 Wormholes(SPFA判负环)

    题目链接:http://poj.org/problem?id=3259 题目大意是给你n个点,m条双向边,w条负权单向边.问你是否有负环(虫洞). 这个就是spfa判负环的模版题,中间的cnt数组就是 ...

  2. Poj 3259 Wormholes(spfa判负环)

    Wormholes Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 42366 Accepted: 15560 传送门 Descr ...

  3. spfa判负环

    bfs版spfa void spfa(){ queue<int> q; ;i<=n;i++) dis[i]=inf; q.push();dis[]=;vis[]=; while(!q ...

  4. poj 1364 King(线性差分约束+超级源点+spfa判负环)

    King Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14791   Accepted: 5226 Description ...

  5. 2018.09.24 bzoj1486: [HNOI2009]最小圈(01分数规划+spfa判负环)

    传送门 答案只保留了6位小数WA了两次233. 这就是一个简单的01分数规划. 直接二分答案,根据图中有没有负环存在进行调整. 注意二分边界. 另外dfs版spfa判负环真心快很多. 代码: #inc ...

  6. BZOJ 4898 [APIO2017] 商旅 | SPFA判负环 分数规划

    BZOJ 4898 [APIO2017] 商旅 | SPFA判负环 分数规划 更清真的题面链接:https://files.cnblogs.com/files/winmt/merchant%28zh_ ...

  7. [P1768]天路(分数规划+SPFA判负环)

    题目描述 “那是一条神奇的天路诶~,把第一个神犇送上天堂~”,XDM先生唱着这首“亲切”的歌曲,一道猥琐题目的灵感在脑中出现了. 和C_SUNSHINE大神商量后,这道猥琐的题目终于出现在本次试题上了 ...

  8. LightOj 1221 - Travel Company(spfa判负环)

    1221 - Travel Company PDF (English) Statistics problem=1221" style="color:rgb(79,107,114)& ...

  9. poj 2049(二分+spfa判负环)

    poj 2049(二分+spfa判负环) 给你一堆字符串,若字符串x的后两个字符和y的前两个字符相连,那么x可向y连边.问字符串环的平均最小值是多少.1 ≤ n ≤ 100000,有多组数据. 首先根 ...

  10. BZOJ 1715: [Usaco2006 Dec]Wormholes 虫洞 DFS版SPFA判负环

    Description John在他的农场中闲逛时发现了许多虫洞.虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前).John的每个农场有M条小路(无向边)连接着N ...

随机推荐

  1. DB2 索引(2)

    最近研究了一点DB2索引相关的东西,做一个总结: (1)在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构: (2)在经常用连接的列(join)上建索引,这些列主要是一些外键,可以加快连接的速 ...

  2. win7和Ubuntu16.04之间相互远程控制

    一.在win7中远程控制ubuntu16.04 步骤: 在ubuntu中通过Desktop share打开允许远程访问 ubuntu中安装xrdp 由于xrdp与unity.gnome桌面不兼容,所以 ...

  3. Keras.NET

    [翻译]Keras.NET简介 - 高级神经网络API in C#   Keras.NET是一个高级神经网络API,它使用C#编写,并带有Python绑定,可以在Tensorflow.CNTK或The ...

  4. Maven工具-简介

    Maven工具-简介 定义 ①maven是一款服务于java平台的自动化构建工具 make→Ant→maven→Gradle ②构建 [1]概念:以"java源文件"." ...

  5. TypeScript 高级类型 类(class)

    传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员来讲就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来的. 从ECMAScript ...

  6. zblog安装环境介绍?zblog安装需要什么环境

    最近在群里看到很的多人有在问:“安装zblog需要什么环境?”,其实这个问题在zblog官网的程序下载页面有说明,但是不太详细,那么本文的目的就是来给大家介绍下zblog安装环境详细说明. zblog ...

  7. sendmail邮箱部署设置

    前言:在使用一些shell脚本进行监控时需要通过发送报警邮件来提醒,下面通过部署简单的sendmail来实现简单的邮件发送. 1.安装 mailx 和 sendmail: yum install ma ...

  8. WUSTOJ 1299: 结点选择(Java)

    题目链接:

  9. Maven学习存档(2)——settings.xml配置

    二.settings.xml配置 2.1 原文 <?xml version="1.0" encoding="UTF-8"?> <!-- Lic ...

  10. 手写PE结构解析工具

    PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如 ...