当然,对于Spfa判负环,实际上还有优化:就是把判断单个点的入队次数大于n改为:如果总的点入队次数大于所有点两倍

时有负环,或者单个点的入队次数大于sqrt(点数)有负环。这样时间复杂度就降了很多了。

判断给定的有向图中是否存在负环。

利用 spfa 算法判断负环有两种方法:

1) spfa 的 dfs 形式,判断条件是存在一点在一条路径上出现多次。

2) spfa 的 bfs 形式,判断条件是存在一点入队次数大于总顶点数。

代码如下:

法 1 (spfa 的 dfs 形式):

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int oo = 1 << 30;

const int maxn = 1010;

struct Edge {

int u, v, t, next;

}edge[2010];

int prev[maxn], p[maxn], d[maxn];

bool vis[maxn], flag;

int tot;

void addEdge(int u, int v, int t) {

edge[tot].u = u;

edge[tot].v = v;

edge[tot].t = t;

edge[tot].next = prev[u];

prev[u] = tot ++;

}

void spfa(int u) {

int v;

for (int i = prev[u]; i != -1; i = edge[i].next) {

v = edge[i].v;

if (d[u] + edge[i].t < d[v]) {

if (vis[v]) {            //存在一点在一条路径上出现多次

flag = true;

return ;

}

else {

d[v] = d[u] + edge[i].t;

vis[v] = true;

spfa(v);

}

}

}

}

int main() {

//freopen("input.txt", "r", stdin);

//freopen("output.txt", "w", stdout);

int T;

int a, b, t;

int n, m;

scanf("%d", &T);

while (T --) {

scanf("%d%d", &n, &m);

memset(prev, -1, sizeof(prev));

tot = 0;

for (int i = 1; i <= m; i ++) {

scanf("%d%d%d", &a, &b, &t);

addEdge(a, b, t);

}

memset(vis, false, sizeof(vis));

fill(d, d + n, oo);

d[0] = 0;

flag = false;

spfa(0);

if (flag) printf("possible\n");

else printf("not possible\n");

}

return 0;

}

法 2 (spfa 的 bfs 形式):

#include <iostream>

#include <cstdio>

#include <cstring>

#include <queue>

using namespace std;

const int oo = 1 << 30;

const int maxn = 1010;

struct Edge {

int u, v, t, next;

}edge[2010];

int prev[maxn], p[maxn], d[maxn], in[maxn];

bool vis[maxn];

int tot;

queue<int> q;

void addEdge(int u, int v, int t) {

edge[tot].u = u;

edge[tot].v = v;

edge[tot].t = t;

edge[tot].next = prev[u];

prev[u] = tot ++;

}

bool spfa(int n) {

int u, v;

while (!q.empty()) q.pop();

memset(vis, false, sizeof(vis));

memset(in, 0, sizeof(in));

fill(d, d + n, oo);

d[0] = 0; vis[0] = true;

q.push(0);

while (!q.empty()) {

u = q.front();

vis[u] = false;

for (int i = prev[u]; i != -1; i = edge[i].next) {

v = edge[i].v;

if (d[u] + edge[i].t < d[v]) {

d[v] = d[u] + edge[i].t;

if (!vis[v]) {

in[v] ++;

if (in[v] > n) return true;                //存在一点入队次数大于总顶点数

vis[v] = true;

q.push(v);

}

}

}

vis[u] = false;

q.pop();

}

return false;

}

int main() {

//freopen("input.txt", "r", stdin);

//freopen("output.txt", "w", stdout);

int T;

int a, b, t;

int n, m;

scanf("%d", &T);

while (T --) {

scanf("%d%d", &n, &m);

memset(prev, -1, sizeof(prev));

tot = 0;

for (int i = 1; i <= m; i ++) {

scanf("%d%d%d", &a, &b, &t);

addEdge(a, b, t);

}

if (spfa(n)) printf("possible\n");

else printf("not possible\n");

}

return 0;

}

spfa 判断负环 (转载)的更多相关文章

  1. POJ 3259 Wormholes【最短路/SPFA判断负环模板】

    农夫约翰在探索他的许多农场,发现了一些惊人的虫洞.虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的N(1≤N≤500)个农场被编号为1..N,之间有M(1≤M≤2500)条路径 ...

  2. spfa判断负环

    会了spfa这么长时间竟然不会判断负环,今天刚回.. [例题]poj3259 题目大意:当农场主 John 在开垦他的农场时,他发现了许多奇怪的昆虫洞.这些昆虫洞是单向的,并且可以把你从入口送到出口, ...

  3. Wormholes---poj3259(最短路 spfa 判断负环 模板)

    题目链接:http://poj.org/problem?id=3259 题意是问是否能通过虫洞回到过去: 虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts. 我们把虫洞看成是一条负权路,问 ...

  4. POJ 3259 Wormholes ( SPFA判断负环 && 思维 )

    题意 : 给出 N 个点,以及 M 条双向路,每一条路的权值代表你在这条路上到达终点需要那么时间,接下来给出 W 个虫洞,虫洞给出的形式为 A B C 代表能将你从 A 送到 B 点,并且回到 C 个 ...

  5. Extended Traffic LightOJ - 1074 spfa判断负环

    //判断负环 在负环内的城市输出? #include <iostream> #include <queue> #include <cstdio> #include ...

  6. Wormholes POJ - 3259 spfa判断负环

    //判断负环 dist初始化为正无穷 //正环 负无穷 #include<iostream> #include<cstring> #include<queue> # ...

  7. UVA 558 SPFA 判断负环

    这个承认自己没看懂题目,一开始以为题意是形成环路之后走一圈不会产生负值就输出,原来就是判断负环,用SPFA很好用,运用队列,在判断负环的时候,用一个数组专门保存某个点的访问次数,超过了N次即可断定有负 ...

  8. POJ3259 Wormholes(SPFA判断负环)

    Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes ...

  9. L - The Shortest Path Gym - 101498L (dfs式spfa判断负环)

    题目链接:https://cn.vjudge.net/contest/283066#problem/L 题目大意:T组测试样例,n个点,m条边,每一条边的信息是起点,终点,边权.问你是不是存在负环,如 ...

随机推荐

  1. PrintWriter 和 Scanner 类的组合使用

    // 示例程序:将一个Employee记录数组存储成一个文本文件,其中每个记录都保存在单独的一行中, // 而实例的域彼此之间使用分隔符分离开. // 众所周知: // 以二进制格式写出数据,需要使用 ...

  2. 一劳永逸的搞定 FLEX 布局(转)

    一劳永逸的搞定 flex 布局 寻根溯源话布局 一切都始于这样一个问题:怎样通过 CSS 简单而优雅的实现水平.垂直同时居中.记得刚开始学习 CSS 的时候,看到 float 属性不由得感觉眼前一亮, ...

  3. 在Linux下面的某一个文件的查找命令

    借鉴文章:https://www.kafan.cn/edu/60044166.html Linux查找包含特定字符串的文件名的方法:http://www.jbxue.com/LINUXjishu/97 ...

  4. ELK系列一:ELK的安装

    一.Elasticsearch.Kibana.Logstash.Elasticsearch-head的安装 ELK的安装 安装下载地址: https://www.elastic.co/cn/downl ...

  5. async 与await

    一. async 与await (https://segmentfault.com/a/1190000007535316) 1.async 是“异步”的简写,而 await 可以认为是 async w ...

  6. 剑指offer题目记录

    1.如下为类型CMyString的声明,请为该类型添加赋值运算符函数. class CMyString { public: CMyString(char* pData = NULL); CMyStri ...

  7. MFC创建好的对话框如何移植到新程序中

    1.用文本文件打开需要移植对话框工程中的rc文件 2.在RC文件夹中找到需要移植的对话框内容,然后拷贝到新的工程的rc文件中 3.在原有工程的rsource.h中所有和这个对话框有关的ID都拷贝到新的 ...

  8. Android开发中Chronometer的用法

    Chronometer集成自TextView,里面有个Handler负责定时更新ui. 其计时原理很简单:通过setBase(long t)方法设置好baseTime之后,当start()时,每隔一秒 ...

  9. Shell sleep指定延迟时间

    可以给时间,让上一条命令执行完毕后,并且退出 sleep 1 睡眠1秒sleep 1s 睡眠1秒sleep 1m 睡眠1分sleep 1h 睡眠1小时

  10. numpy协方差矩阵numpy.cov

    numpy.cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None, aweights=None)[source] Estim ...