负环、差分约束和传递闭包
负环
判负环:如果 \(n-1\) 次之后依然存在可以松弛的边,那么就是存在负环。(负环永远可以松弛)
对于 spfa:看看有没有哪个元素入队 \(n\) 次。
代码:(有负环 YES,否则 NO)
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9;
void cmax(int &x, int y) {if(x < y) x = y;}
void cmin(int &x, int y) {if(x > y) x = y;}
vector<pii> g[2010];int n, m;
int dis[2010];
const int v = 10000;
void bellman_ford() {
f(i, 1, n - 1) {
f(j, 1, n) {
for(pii kw : g[j]) {
int k = kw.first, w = kw.second;
if(dis[k] > dis[j] + w) {
dis[k] = dis[j] + w;
}
}
}
}
f(j, 1, n) {
for(pii kw : g[j]) {
int k = kw.first, w = kw.second;
if(dis[k] > dis[j] + w) {
cout << "YES\n";
return;
}
}
}
cout << "NO\n";
return;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(NULL);
cout.tie(NULL);
//time_t start = clock();
//think twice,code once.
//think once,debug forever.
int T; cin >> T;
while(T--) {
cin >> n >> m;
f(i, 1, n) g[i].clear();
f(i, 1, m) {
int u, v, w; cin >> u >> v >> w;
if(w < 0) {
g[u].push_back({v, w});
}
else {
g[v].push_back({u, w});
g[u].push_back({v, w});
}
}
f(i, 1, n) dis[i] = inf;
dis[1] = 0;
bellman_ford();
}
//time_t finish = clock();
//cout << "time used:" << (finish-start) * 1.0 / CLOCKS_PER_SEC <<"s"<< endl;
return 0;
}
差分约束
差分约束系统 是一种特殊的 \(n\) 元一次不等式组,它包含 \(n\) 个变量 \(x_1,...,x_n\) 以及 \(m\) 个约束条件,每个约束条件是由两个其中的变量做差构成的,形如 \(x_i - x_j \le c_k\),其中 \(1 \le i, j \le n, i \neq j, 1 \le k \le m\) 并且 \(c_k\) 是常数(可以是非负数,也可以是负数)。我们要解决的问题是:求一组解 \(x_1=a_1,...,x_n=a_n\),使得所有的约束条件得到满足,否则判断出无解。
差分约束系统中的每个约束条件 \(x_i - x_j \le c_k\) 都可以变形成 \(x_i \le x_j + c_k\),这与单源最短路中的三角形不等式 \(dist[y] \le dist[x] + z\) 非常相似。因此,我们可以把每个变量 看做图中的一个结点,对于每个约束条件 \(x_i - x_j \le c_k\),从结点 \(j\) 向结点 \(i\) 连一条长度为 \(c_k\) 的有向边。
注意到,如果 \(\{a_1, ..., a_n\}\) 是该差分约束系统的一组解,那么对于任意的常数 \(d\),\(\{a_1+d, ..., a_n+d\}\) 显然也是该差分约束系统的一组解,因为这样做差后 \(d\) 刚好被消掉。
过程
设 \(dist[0] = 0\) 并向每一个点连一条权重为 \(0\) 边,跑单源最短路,若图中存在负环,则给定的差分约束系统无解,否则,\(x_i = dist[i]\) 为该差分约束系统的一组解。
时间复杂度 \(O(nm)\)。
原理
对于一个环,假设两个相邻点编号为 \(i,j\)。如果存在负环,那么 \(w_i - w_j \le a_1\),\(w_i - w_j \ge -a_2\),且 \(a_1 + a_2 < 0\),也即 \(a_1 \le -a_2\)。显然矛盾。
否则,对于 \(w_i - w_j \le a\),在图上体现了 \(d_i \le d_j + a\) 的限制。(从 \(j\) 连向 \(i\))而 \(d_i\) 体现为 \(0\) 到 \(i\) 的距离。
扩展
考虑差分约束系统 \(\cfrac{w_i}{w_j} \le c_k\) 的求解方式。就是把每个数字取 \(\log\) 即可。
传递闭包
floyd,但是每条边表示某一种关系 \(rel_{i, j}\)。对于 \(rel_{i, j}\) 和 \(rel_{j, k}\),可以维护将其合并到 \(rel_{i, k}\)。
具体地,它是一个布尔矩阵,满足 \(i\) 可达 \(j\) 的时候为 \(1\) 否则为 \(0\)。那么用 floyd 就是求可达性的过程,十分自然。
求出来的结果是一个偏序图。