- BC20280018's blog
负环模板
- 2025-9-13 15:30:14 @
负环模板
题目描述
给定一个 个点的有向图,请求出图中是否存在从顶点 出发能到达的负环。
负环的定义是:一条边权之和为负数的回路。
输入格式
本题单测试点有多组测试数据。
输入的第一行是一个整数 ,表示测试数据的组数。对于每组数据的格式如下:
第一行有两个整数,分别表示图的点数 和接下来给出边信息的条数 。
接下来 行,每行三个整数 。
- 若 ,则表示存在一条从 至 边权为 的边,还存在一条从 至 边权为 的边。
- 若 ,则只表示存在一条从 至 边权为 的边。
输出格式
对于每组数据,输出一行一个字符串,若所求负环存在,则输出 YES
,否则输出 NO
。
输入输出样例 #1
输入 #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
说明/提示
数据规模与约定
对于全部的测试点,保证:
- ,。
- ,。
- 。
提示
请注意, 不是图的边数。
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
const int M = 20005;
const long long inf = INT_MAX;
int n, m, cnt0;
int dis[N], vis[N], head[N], cnt[N];
struct edge
{
int nxt, to, dis;
} g[M];
void addedge(int u, int v, int w)
{
g[++cnt0].nxt = head[u];
g[cnt0].to = v;
g[cnt0].dis = w;
head[u] = cnt0;
}
bool spfa()
{
queue<int> q;
for (int i = 1; i <= n; i++)
{
dis[i] = inf;
vis[i] = 0;
}
q.push(1);
dis[1] = 0;
vis[1] = 1;
cnt[1]++;
while (!q.empty())
{
int u = q.front();
q.pop();
vis[u] = 0;
for (int i = head[u]; i; i = g[i].nxt)
{
int v = g[i].to;
if (dis[v] > dis[u] + g[i].dis)
{
dis[v] = dis[u] + g[i].dis;
if (vis[v] == 0)
{
vis[v] = 1;
q.push(v);
cnt[v]++;
if (cnt[v] > n)
return 1;
}
}
}
}
return 0;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
memset(dis, 0, sizeof(dis));
memset(vis, 0, sizeof(vis));
memset(cnt, 0, sizeof(cnt));
memset(g, 0, sizeof(g));
memset(head, 0, sizeof(head));
cnt0 = 0;
scanf("%d%d", &n, &m);
for (int i = 1, u, v, w; i <= m; i++)
{
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
if (w >= 0)
addedge(v, u, w);
}
if (spfa())
printf("YES\n");
else
printf("NO\n");
}
return 0;
}