简介

对于一个不存在负环的图,从起点到任意一个点最短距离经过的点最多只有 n 个。用 cnt[i] 表示从起点(假设是 1)到i的最短距离包含点的个数,初始化 cnt[1]=1,那么当我们能够用点u松弛点v时,松弛时同时更新cnt[v] = cnt[u]+1,若发现此时 cnt[v] > n,那么就存在负环
还有一种方法是记录每个点的入队次数,入队次数大于 n 就说明有负环,但是这样做一般都要比上面的方法慢。举个例子,在一个由 n 个点构成的负环中,这个方法要绕环n次,而上面的方法绕环 1 次就行了

例题

Luogu-P3385

模板题
第一种方案

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<cstring>
#include<algorithm>
#define lson x<<1
#define rson x<<1|1
#define ll long long
#define rint register int
#define mid  ((L + R) >> 1)
using namespace std;
template <typename xxx> inline void read(xxx &x) {
    char c = getchar(),f = 1;x = 0;
    for(;c ^ '-' && !isdigit(c);c = getchar());
    if(c == '-') c = getchar(),f = -1;
    for(;isdigit(c);c = getchar()) x = (x<<1) + (x<<3) + (c ^ '0');
    x *= f;
}
template<typename xxx>void print(xxx x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
const int maxn = 100010;
const int inf = 0x7fffffff;
const int mod = 1e9 + 7;
struct edge {
    int to,last,val;
}e[maxn];
int head[maxn],tot;
inline void add(int from,int to,int val) {
    ++tot;
    e[tot].to = to;
    e[tot].val = val;
    e[tot].last = head[from];
    head[from] = tot;
}
int n,m;
int dis[maxn],vis[maxn],tim[maxn];
inline int spfa() {
    queue<int>q;
    for(rint i = 0;i <= n; ++i) {
        dis[i] = inf;
        vis[i] = 0;
        tim[i] = 0;
    }
    q.push(1);dis[1] = 0;tim[1] = 1;
    while(q.size()) {
        int x = q.front();q.pop();vis[x] = 0;
        for(rint i = head[x];i;i = e[i].last) {
            if(dis[e[i].to] > dis[x] + e[i].val) {
                dis[e[i].to] = dis[x] + e[i].val;
                tim[e[i].to] = tim[x] + 1;
                if(tim[e[i].to] > n) return 1;
                if(!vis[e[i].to]) {
                    vis[e[i].to] = 1;
                    q.push(e[i].to);
                }
            }
        }
    }
    return 0;
}
int main() {
    int t;read(t);
    while(t--) {
        tot = 0;
        memset(head,0,sizeof(head));
        read(n);read(m);
        for(rint i = 1;i <= m; ++i) {
            int a,b,c;
            read(a);read(b);read(c);
            add(a,b,c);
            if(c >= 0) add(b,a,c);
        }
        if(spfa()) printf("YE5\n");
        else printf("N0\n");
    }
    return 0;
}
/*

*/

第二种方案(实测着实慢很多)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<cstring>
#include<algorithm>
#define lson x<<1
#define rson x<<1|1
#define ll long long
#define rint register int
#define mid  ((L + R) >> 1)
using namespace std;
template <typename xxx> inline void read(xxx &x) {
    char c = getchar(),f = 1;x = 0;
    for(;c ^ '-' && !isdigit(c);c = getchar());
    if(c == '-') c = getchar(),f = -1;
    for(;isdigit(c);c = getchar()) x = (x<<1) + (x<<3) + (c ^ '0');
    x *= f;
}
template<typename xxx>void print(xxx x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
const int maxn = 100010;
const int inf = 0x7fffffff;
const int mod = 1e9 + 7;
struct edge {
    int to,last,val;
}e[maxn];
int head[maxn],tot;
inline void add(int from,int to,int val) {
    ++tot;
    e[tot].to = to;
    e[tot].val = val;
    e[tot].last = head[from];
    head[from] = tot;
}
int n,m;
int dis[maxn],vis[maxn],tim[maxn];
inline int spfa() {
    queue<int>q;
    for(rint i = 0;i <= n; ++i) {
        dis[i] = inf;
        vis[i] = 0;
        tim[i] = 0;
    }
    q.push(1);dis[1] = 0;
    while(q.size()) {
        int x = q.front();q.pop();vis[x] = 0;
        if(tim[x] == n) return 1;
        ++tim[x];
        for(rint i = head[x];i;i = e[i].last) {
            if(dis[e[i].to] > dis[x] + e[i].val) {
                dis[e[i].to] = dis[x] + e[i].val;
                if(!vis[e[i].to]) {
                    vis[e[i].to] = 1;
                    q.push(e[i].to);
                }
            }
        }
    }
    return 0;
}
int main() {
//  freopen("my.out","w",stdout);
    int t;read(t);
    while(t--) {
        tot = 0;
        memset(head,0,sizeof(head));
        read(n);read(m);
        for(rint i = 1;i <= m; ++i) {
            int a,b,c;
            read(a);read(b);read(c);
            add(a,b,c);
            if(c >= 0) add(b,a,c);
        }
        if(spfa()) printf("YE5\n");
        else printf("N0\n");
    }
    return 0;
}
/*

*/
01-04 11:18