原题链接:
题解:
ballman_ford以及spfa都可以用于判断负环
代码:
相比之下,还是spfa效果更好一些
Ballman_ford判断:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e3 + 10, M = 1e4 + 10;
struct Edge {
int a, b, w;
}edge[M];
int dis[N];
int n, m, k;
string bellman_ford() {
bool flag = true;
int cnt = 0;
while (flag)
{
flag = false;
cnt++;
if (cnt > n) return "Yes"; //迭代超过n次根据抽屉原理出现了n+1个点既出现了负环
for (int i = 0;i < m;i++)
{
int a = edge[i].a, b = edge[i].b, w = edge[i].w;
if (dis[b] > dis[a] + w)
{
flag = true;
dis[b] = dis[a] + w;
}
}
}
return "No";
}
int main() {
cin >> n >> m;
for (int i = 0;i < m;i++) {
int x, y, z;cin >> x >> y >> z;
edge[i] = { x,y,z };
}
cout << bellman_ford();
}
Spfa判断:
#pragma GCC optimize(2, 3, "Ofast", "inline")
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int dis[N], state[N], cnt[N];//cnt[] 表示 当前从1-x的最短路的边数
vector<pair<int, int>> v[N];//存储的是终点编号-距离
int n, m;
bool spfa() {
// 这里不需要初始化dist数组为 正无穷/初始化的原因是, 如果存在负环, 那么dist不管初始化为多少, 都会被更新
queue<int> q;
for (int i = 1;i <= n;i++) {//不仅仅是1了, 因为点1可能到不了有负环的点, 因此把所有点都加入队列
q.push(i);
state[i] = 1;
}
while (q.size()) {
int F = q.front();
q.pop();
state[F] = 0;
for (int i = 0;i < v[F].size();i++) {
int y = v[F][i].first, z = v[F][i].second;
if (dis[y] > dis[F] + z) {
dis[y] = dis[F] + z;
cnt[y] = cnt[F] + 1;
if (cnt[y] >= n)
return true;
if (!state[y]) {
q.push(y);
state[y] = 1;
}
}
}
}
return false;
}
int main() {
cin >> n >> m;
for (int i = 0;i < m;i++) {
int x, y, z;cin >> x >> y >> z;
v[x].push_back({ y,z });
}
bool t = spfa();
cout << (t ? "Yes" : "No");
}