SPFA判负环模板

题目描述

给定一个 nnn 个点的有向图,请求出图中是否存在从顶点 111 出发能到达的负环。

负环的定义是:一条边权之和为负数的回路。

输入格式

本题单测试点有多组测试数据

输入的第一行是一个整数 TTT,表示测试数据的组数。对于每组数据的格式如下:

第一行有两个整数,分别表示图的边数 nnn 和接下来给出边信息的条数 mmm。

接下来 mmm 行,每行三个整数 u,v,wu, v, wu,v,w。

  • w≥0w geq 0w0,则表示存在一条从 uuu 至 vvv 边权为 www 的边,还存在一条从 vvv 至 uuu 边权为 www 的边。
  • w<0w < 0w<0,则只表示存在一条从 uuu 至 vvv 边权为 www 的边。

输出格式

对于每组数据,输出一行一个字符串,若所求负环存在,则输出 YES,否则输出 NO

输入输出样例

输入 #1
2
3 4
1 2 2
1 3 4
2 3 1
3 1 -3
3 3
1 2 3
2 3 4
3 1 -8
输出 #1
NO
YES

负环即边权和为负数的环。
重要性质:两点之间存在负环时,必然没有最短路。(因为路径越更新越小
原理:lyd的书上有言:从起点到x的最短路包含了>=n条边,说明肯定有节点被重复经过了,故最短路径上存在环且环上各个点能更新下一个点的dist值。
设cnt[x]表示从1到x的最短路包含的边数,当更新d[y]=d[x]+z时也同时更新cnt[y]=cnt[x]+1。当有cnt[y]>=n时直接退出即可。
#include <bits/stdc++.h>
#define N 2005
#define M 3005
using namespace std;
int n,m,tot=0;
int head[N],edge[2*M],ver[2*M],Next[2*M],cnt[N],d[N];
bool v[N];
void add(int x,int y,int z)
{
    ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
}
bool spfa()
{
    queue<int>q;
    d[1]=0,v[1]=1,cnt[1]=0;
    q.push(1);
    while(q.size())
    {
        int x=q.front();
        q.pop();
        v[x]=0;
        int i;
        for(i=head[x];i;i=Next[i])
        {
            int y=ver[i],z=edge[i];
            if(d[y]>d[x]+z)
            {
                d[y]=d[x]+z;
                cnt[y]++;
                if(cnt[y]>=n)return 1;
                if(!v[y])q.push(y),v[y]=1;
            }
        }
    }
    return 0;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(head,0,sizeof(head));
        memset(edge,0,sizeof(edge));
        memset(ver,0,sizeof(ver));
        memset(Next,0,sizeof(Next));
        memset(cnt,0,sizeof(cnt));
        memset(v,0,sizeof(v));
        memset(d,0x3f,sizeof(d));
        tot=0;
        cin>>n>>m;
        int i,u,v,w;
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            if(w>=0)add(v,u,w);
        }
        if(spfa())cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}



原文地址:https://www.cnblogs.com/lipoicyclic/p/12746433.html