差分约束
1、问题类型描述
-
差分约束是一种特殊的
元一次不等式组,它包含 个变量 以及 个约束条件。- 每个约束条件是由两个其中的变量做差构成的,形如
,其中
- 每个约束条件是由两个其中的变量做差构成的,形如
-
我们要解决的问题是求一组解:
- 使得所有的约束条件得到满足,否则判断出无解。
2、模型转换
-
变形一下:
- 容易发现,与最短路中的
非常相似
- 容易发现,与最短路中的
-
如何理解?
-
我们就将不等式问题转换成为一个最短路径问题
-
我们可以把每个变量
看做图中的一个结点,对于每个约束条件 ,看做从结点 向结点 连一条长度为 的有向边。 -
注意到,如果
是该差分约束系统的一组解,那么对于任意的常数 , 显然也是该差分约束系统的一组解,因为这样做差后 刚好被消掉。
-
3、不等式组无解
-
什么情况下,上面的多项式组无解?
-
在我们转换的模型中,如果一个点的最短距离
不存在,即负无穷大 → 存在负环 -
在原来的方程组里面,就是几个变量相互约束
-
所以就是利用
判断负环的办法即可,即存在
4、为什么不能用Dijkstra
故只能使用
5、拓展
-
题目给的形式为
-
若为
- 则将两边同时乘以负号,有
- 则将两边同时乘以负号,有
-
若为
,即上面二者的统一 且 ,建两条边即可
6、代码实现
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct node{
int a,b;
};
int n, m;
vector<node> v[N];
int num[N], dis[N];
bool in[N];
int main() {
cin >> n >> m;
queue<int> q;
for (int i = 1; i <= m; i ++ ) {
int x, y, w;
cin >> y >> x >> w;
v[x].push_back({y, w});
}
for (int i = 1; i <= n; i++) {
v[0].push_back({i, 0});
}
memset(dis, 0x3f, sizeof dis);
dis[0] = 0;
q.push(0);
while (!q.empty()) {
int x = q.front();
q.pop();
num[x]++;
in[x] = false;
if (num[x] > n + 1) {
cout << "NO";
exit(0);
}
for (int i = 0; i < v[x].size(); i++) {
int u = v[x][i];
if (dis[u] > dis[x] + v[x][i].b) {
dis[u] = dis[x] + v[x][i].b;
if (!in[u]) {
in[u] = true;
q.push(u);
}
}
}
}
for (int i = 1; i <= n; i++) {
cout << dis[i] <<" ";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】