spfa求负环
【模板】负环
题目描述
给定一个 \(n\) 个点的有向图,请求出图中是否存在从顶点 \(1\) 出发能到达的负环。
负环的定义是:一条边权之和为负数的回路。
本题单测试点有多组测试数据。
输入的第一行是一个整数 \(T\),表示测试数据的组数。对于每组数据的格式如下:
第一行有两个整数,分别表示图的点数 \(n\) 和接下来给出边信息的条数 \(m\)。
接下来 \(m\) 行,每行三个整数 \(u, v, w\)。
- 若 \(w \geq 0\),则表示存在一条从 \(u\) 至 \(v\) 边权为 \(w\) 的边,还存在一条从 \(v\) 至 \(u\) 边权为 \(w\) 的边。
- 若 \(w < 0\),则只表示存在一条从 \(u\) 至 \(v\) 边权为 \(w\) 的边。
对于每组数据,输出一行一个字符串,若所求负环存在,则输出 YES,否则输出 NO。
根据鸽巢定理每个点至多被入队\(n\)次,spfa判断入队次数不大于点数即可
核心代码:
if(++cnt[y] >= n)
{
puts("YES");
return;
}
全部代码
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N = 20005,M = 30003;
int h[N],w[M],e[M],ne[M],idx;
int n,m;
bool v[N];
int d[N],cnt[N];
queue<int>q;
void add(int x,int y,int z)
{
e[++idx] = y,w[idx] = z;
ne[idx] = h[x],h[x] = idx;
}
void spfa()
{
memset(d,0x3f,sizeof d);
memset(v,0,sizeof v);
memset(cnt,0,sizeof cnt);
d[1] = 0,v[1] = 1;
cnt[1] = 0;
q.push(1);
while(q.size())
{
int x = q.front();q.pop();
v[x] = 0;
for(int i = h[x] ; i ;i = ne[i])
{
int y = e[i],z = w[i];
if(d[y] > d[x] + z)
{
d[y] = d[x] + z;
if(!v[y])
{
if(++cnt[y] >= n)
{
puts("YES");
return;
}
q.push(y),v[y] = 1;
}
}
}
}
puts("NO");
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(h,0,sizeof h);
memset(e,0,sizeof e);
memset(ne,0,sizeof ne);
memset(w,0,sizeof w);
idx = 0;
scanf("%d%d",&n,&m);
while(m--)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(z < 0)
add(x,y,z);
else
{
add(x,y,z);
add(y,x,z);
}
}
spfa();
}
}
“风雪越是呼啸,雪莲越是绽放”

浙公网安备 33010602011771号