题解:P3385 【模板】负环
由于某些原因,导致这道题不卡 SPFA,所以可以用 SPFA 来做。
SPFA 类似 BFS,但是只要某个节点如果【从
然而有这样一种图,它是带有负环的。负环:边的权值总和为负数的环。如果最短路走到了负环中的节点,那么它就可以绕着这个环走,越走它的权值越小,一圈圈走下去,最终到达负无穷。那此时最短路就没有意义了,因此我们需要判断负环。
SPFA 中如果一个节点被走到了超过
详见代码。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 2e3 + 10;
ll n, m, f[maxn], vis[maxn];
vector<pair<ll, ll> > edge[maxn];
queue<ll> q;
void solve()
{
cin >> n >> m;
for (ll i = 1; i <= n; i++) // 十年 OI 一场空,多测不清见祖宗
{
edge[i].clear();
f[i] = 0x3f3f3f3f'3f3f3f3f; // 注意赋成 INF
vis[i] = 0;
}
while (!q.empty())
{
q.pop();
}
while (m--)
{
ll u, v, w;
cin >> u >> v >> w;
edge[u].push_back({v, w});
if (w >= 0) // 注意读题
{
edge[v].push_back({u, w});
}
}
q.push(1);
f[1] = 0;
bool flag = false;
while (!q.empty())
{
ll u = q.front();
q.pop();
for (auto [v, w] : edge[u]) // C++17 语法
{
if (f[u] + w < f[v]) // 如果可以更新
{
q.push(v); // 那么就更新,并加入队列
f[v] = f[u] + w;
if (++vis[v] > n) // 检测到有负环
{
flag = true;
break;
}
}
}
if (flag)
{
break;
}
}
if (flag)
{
cout << "YES\n";
}
else
{
cout << "NO\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
ll t; cin >> t; while (t--)
solve();
return 0;
}