变形一下: x i ≤ x j + c k x_i\leq x_j + c_k xi≤xj+ck
如何理解?
如果 u u u与 v v v之间有一条连边,那么 d i v [ v ] div[v] div[v]的值,要嘛 = = d i s [ u ] + w ==dis[u]+w ==dis[u]+w,要嘛 < d i s [ u ] + w <dis[u]+w <dis[u]+w
因为有那条连边在哪,所以可以被松弛操作,只要是 d i s [ v ] > d i s [ u ] + w dis[v]>dis[u]+w dis[v]>dis[u]+w,那么这个情况就可以被松弛
然后我们就将不等式问题转换成为一个最短路径问题
接下来我们的 x [ 1 − n ] x[1-n] x[1−n]就等价于 d i s [ 1 − n ] dis[1-n] dis[1−n]了,然后我们要求解的就是 d i s [ 1 − n ] dis[1-n] dis[1−n]了,即求解最短路
只要存在有向边边,就满足那个不等式的条件,跑最短路求出所有的最短距离 d i s [ ] dis[~] dis[ ]即可
源点如何选取?
因为是有向图,我们要遍历到所有节点,所以需要建立一个超级源点0号
什么情况下,上面的多项式组无解?
在我们转换的模型中,如果一个点的最短距离 d i s [ i ] dis[i] dis[i]不存在,即非负无穷大——>存在负环
在原来的方程组里面,就是几个变量相互约束
所以就是利用SPFA
判断负环的办法即可,即存在num[i]>n
题目给的形式为 x i − x j ≤ c k x_i-x_j\le c_k xi−xj≤ck
若为 x i − x j ≥ c k x_i-x_j\ge c_k xi−xj≥ck
若为 x i − x j = c k x_i-x_j=c_k xi−xj=ck,即上面二者的统一
#include <bits/stdc++.h> #include <bits/extc++.h> #include <unordered_map> #include <unordered_set> using namespace std; using namespace __gnu_cxx; using namespace __gnu_pbds; #define debug(x) cerr << #x << ": " << x << '\n'; #define bd cerr << "----------------------" << el; #define el '\n' #define cl putchar('\n'); #define pb push_back #define eb emplace_back #define x first #define y second #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define lop(i, a, b) for (int i = (a); i < (b); i++) #define dwn(i, a, b) for (int i = (a); i >= (b); i--) #define ceil(a, b) (a + (b - 1)) / b #define ms(a, x) memset(a, x, sizeof(a)) #define INF 0x3f3f3f3f #define db double #define all(x) x.begin(),x.end() #define cmax(a, b) a = max(a, b) #define cmin(a, b) a = min(a, b) #define reps(i, x) for (int i = 0; i < x.size(); i++) typedef long long LL; typedef long double LD; typedef pair<int, int> PII; typedef pair<db, db> PDD; typedef vector<int> vci; template <typename T> inline void read(T &x) { x = 0; T f = 1; char c = getchar(); while (!isdigit(c)) { if(c == '-') f = -1; c = getchar(); } while (isdigit(c)) { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } x *= f; } const int N = 1e5 + 10, M = 2e6 + 10, B = 66, md = 1e9 + 7; const double PI = acos(-1), eps = 1e-8; int T, n, m; vector<PII> g[N]; int vis[N], dis[N]; bool inq[N]; int main() { read(n), read(m); queue<int> q; rep(i, 1, m) { int u, v, w; read(v), read(u), read(w); g[u].pb({v, w}); } rep(i, 1, n) { g[0].pb({i, 0}); //建立0到所有点的边 //这个0只是一个偏移量,你改为任意值都可以 } memset(dis, 0x3f, sizeof dis); dis[0] = 0; q.push(0); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] ++ ; inq[u] = false; if(vis[u] > n + 1) { cout << "NO"; exit(0); } #define v g[u][i].first #define w g[u][i].second reps(i, g[u]) { if (dis[v] > dis[u] + w) { dis[v] = dis[u] + w; if(!inq[v]) { inq[v] = true; q.push(v); } } } #undef v #undef w } rep(i, 1, n) { cout << dis[i]; if( i < n) cout << ' '; } }