当然,对于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. css布局 - 常规上中下分左右布局的一百种实现方法(更新中...)

    一. 上中下左固定 - fixed+margin 概括:如图,此种布局就是顶部.底部和左侧固定不动,只有中间右侧超出可滚动. html: <header>我是头部position: fix ...

  2. CSS改变插入光标颜色caret-color简介及其它变色方法(转)

    一.CSS改变输入框光标颜色的原生属性caret-color CSS caret-color属性可以改变输入框插入光标的颜色,同时又不改变输入框里面的内容的颜色. 例如: input { color: ...

  3. 原生js--insertAdjacentHTML

    insertAdjacentHTML是IE浏览器提供向DOM中插入html字符串的方法,字符串会自动生成在DOM树中. 其调用方式为elem.insertAdjacentHTML( position, ...

  4. Android 4.0的图形硬件加速及绘制技巧

    转:http://zuiniuwang.blog.51cto.com/3709988/721798 从Android 3.0开始,Android 2D的绘制流程就设计为能够更好地支持硬件加速.使用GP ...

  5. how-to-build-c-static-libraries-boost

    http://tungchingkai.blogspot.jp/2016/11/how-to-build-c-static-libraries-boost.html How to build C++ ...

  6. Redis学习笔记--Redis配置文件Sentinel.conf参数配置详解

    redis-sentinel.conf配置项说明如下: 1.port 26379 sentinel监听端口,默认是26379,可以修改. 2.sentinel monitor <master-n ...

  7. sencha touch 自定义事件

    需要添加自定义事件可以如下: this.fireEvent('back', this); 此方法第一个参数为你想要监听的事件,之后的参数为你想要传递的参数一般来说第一个参数最好是控件本身. 同理这个方 ...

  8. OpenStack网络详解

    本博客已经添加"打赏"功能,"打赏"位置位于右边栏红色框中,感谢您赞助的咖啡. Openstack需要对网络有一些了解才能进入openstack的世界,很多都是 ...

  9. ZOJ 3435 Ideal Puzzle Bobble

    ZOJ Problem Set - 3435 Ideal Puzzle Bobble Time Limit: 2 Seconds      Memory Limit: 65536 KB Have yo ...

  10. 网卡bonding模式 - bond0、1、4配置

    网卡bonding模式 - bond0.1.4配置 网卡bonding简介 网卡绑定就是把多张物理网卡通过软件虚拟成一个虚拟的网卡,配置完毕后,所有的物理网卡的ip和mac将会变成相同的.多网卡同时工 ...