SPFA
最短路:保证数据不存在负环的情况下,求1-n最短路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| struct edge { int v, w; }; void solve() { int n, m; cin >> n >> m; vector<vector<edge>> e(n + 1); for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; e[u].push_back({v, w}); } vector<int> dis(n + 1, inf); auto spfa = [&]() { vector<bool> st(n + 1); queue<int> q; q.push(1); st[1] = true; dis[1] = 0; while (q.size()) { auto u = q.front(); q.pop(); st[u] = 0; for (auto [v, w] : e[u]) { if (dis[u] + w < dis[v]) { dis[v] = dis[u] + w; if (st[v] == 0) { q.push(v); st[v] = true; } } } } if (dis[n] == inf) return false; return true; }; for (int i = 1; i <= n; i++) deb(i, dis[i]); if (spfa()) cout << dis[n] << endl; else cout << "impossible" << endl; }
|
判断全局图中是不是存在负环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| struct edge { int v, w; }; void solve() { int n, m; cin >> n >> m; vector<vector<edge>> e(n + 1); for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; e[u].push_back({v, w}); } vector<int> dis(n + 1, inf); vector<int> cnt(n + 1); auto judgefu = [&]() { vector<bool> st(n + 1, 1); queue<int> q; for (int i = 1; i <= n; i++) q.push(i); while (q.size()) { auto u = q.front(); q.pop(); st[u] = 0; for (auto [v, w] : e[u]) { if (dis[u] + w < dis[v]) { dis[v] = dis[u] + w; cnt[v] = cnt[u] + 1; if (cnt[v] >= n) return true; if (st[v] == 0) { q.push(v); st[v] = true; } } } } return false; }; if (judgefu()) cout << "Yes" << endl; else cout << "No" << endl; }
|
从顶点 1出发能到达的负环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| struct edge { int v, w; }; void solve() { int n, m; cin >> n >> m; vector<vector<edge>> e(n + 1); for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; e[u].push_back({v, w}); if (w >= 0) e[v].push_back({u, w}); } vector<int> dis(n + 1, inf); vector<int> cnt(n + 1); auto judgefu = [&]() { vector<bool> st(n + 1, 0); queue<int> q; q.push(1); st[1] = 1; dis[1] = 0; while (q.size()) { auto u = q.front(); q.pop(); st[u] = 0; for (auto [v, w] : e[u]) { if (dis[u] + w < dis[v]) { dis[v] = dis[u] + w; cnt[v] = cnt[u] + 1; if (cnt[v] >= n) return true; if (st[v] == 0) { q.push(v); st[v] = true; } } } } return false; }; if (judgefu()) cout << "YES" << endl; else cout << "NO" << endl; }
|
给出一组包含 m 个不等式,有 n 个未知数的形如:
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧xc1−xc1′≤y1xc2−xc2′≤y2⋯xcm−xcm′≤ym
的不等式组,求任意一组满足这个不等式组的解。
第一行为两个正整数 n,m,代表未知数的数量和不等式的数量。
接下来 m 行,每行包含三个整数 c,c′,y,代表一个不等式 xc−xc′≤y。
一行,n 个数,表示 x1,x2⋯xn 的一组可行解,如果有多组解,请输出任意一组,无解请输出 NO。
一、 求不等式组的可行解
!!!源点需要满足的条件:从源点出发,一定可以走到所有的边。!!!
步骤:
1. 先将每个不等式 xi≤xj+ck,转化成一条从 xj 走到 xi,长度为 ck 的边。
2. 找到一个超级源点,使得该源点一定可以遍历到所有边
3. 从源点求一遍单源最短路
结果1:如果存在负环,则原不等式组一定无解
结果2:如果没有负环,则 dist[i] 就是原不等式组的一个可行解
二、 如何求最大值或者最小值,这里的最值指的是每个变量的最值(独立但可以同时取到)
结论:如果求的是最小值,则应该求最长路;如果求的是最大值,则应该求最短路。
问题:如何转化 xi≤c,其中 c 是一个常数,这类的不等式。
方法:建立一个超级源点0,然后建立 0 -> i 的边,长度是 c 即可。
以求 xi 的最大值为例:
求所有从 xi 出发,构成的多个形如如下的不等式链
xi≤xj+c1≤xk+c2+c1≤⋅⋅⋅≤x0+c1+c2+⋅⋅⋅+cm(x0=0)
所计算出的上界,最终 xi 的最大值等于所有上界的最小值。
这里所有上界的最小值可以理解这么一个例子:
把上述转换成图论的问题,就是求 dist[i] 的最小值,即最短路求解
- 求 xi 的
最小值 时则完全相反,求一个形如如下不等式链所计算出的下界,最终在所有下界里取最大值
xi≥xj+c1≥xk+c2+c1≥⋅⋅⋅≥x0+c1+c2+⋅⋅⋅+cm(x0=0)
转换成图论的问题,就是求 dist[i] 的最大值,即最长路求解
建边技巧:
-
如何转化 xi≤c,其中 c 是一个常数,这类的不等式。
方法:建立一个超级源点0,然后建立 0 -> i 的边,长度是 c 即可。
-
xa−xb≥c→xb≤xa−c→addedge(a,b,−c)
-
xa−xb≤c→addedge(b,a,c)
-
x_a=x_b \to addedge(a,b,0) \and addedge(b,a,0)