欢迎光临 ~|

Laijinyi

园龄:1年7个月粉丝:2关注:2

📂总结
🔖算法
2023-08-04 13:30阅读: 33评论: 0推荐: 0

差分约束总结

差分约束是一个简单的能解一种特殊的 n 元一次不等式组(或者判断无解)的算法,

其中每个不等式形如 xaxbcc 是常数。

差分约束利用了最短路的一个性质:

一个有向图跑完最短路后一定满足对于任意一条边 (x,y,z),有 disydisx+z

这个性质很简单,因为既然有了这样一条边,那么 disy 的范围缩小到最多只能取 disx+z,而且以后还可能继续缩小

然后我们把原来的不等式变换一下:xaxb+c

发现它与上面的不等式很像!

尝试建图,每个未知数 xi 看成是图上的一个节点,

每个约束条件 xixjck 看成一条边

xixj+ck

于是可以建立一条有向边 (j,i,ck) (不用死记硬背,理解了这个就知道为什么这样连边了。。。)

然后跑完最短路后即可满足所有的约束条件。

不过从哪个点作为起点呢?实际上每个点都可以作为起点,所以我们建立一个超级原点 00 连向所有点有一条权值为 0 的边

这样,从节点 0 开始,每个点都可以走到,也就保证解出了所有的未知数。

注意,此时有额外的边 (0,i,0),说明我们约束所有的未知数 xi0

这样跑出来每个 disi 都不是正数...

何时存在无解和无数解?

如果有无法到达的点,则是无数解(这里没有超级原点,因为超级原点是我们为了跑出所有解而人为添加的一个点)

因为这个点无法到达,说明没有边连向它,这就意味着这个点其实是没有约束的,取任意值都满足

如果要判断的话,直接看有没有节点不连边就行

而如果出现了负环,则是无解

因为出现负环意味着根本不存在最短路径,只有更短路径

因为负边权这一存在,迫使我们使用 SPFA 这个死去的算法来帮助我们求解

而且很方便的是,它也能帮助我们判负环(无解)。。。

所以别再管什么生与死,用它就对了!

实际上,最短路求出的解一定是 xi0 时的最大解

因为我们每个 disi 的范围都是从 [,+] 缩小(松弛)到 [,x]

而它最终取的是这个范围内最大的 x

所以是最大解。

意会一下就可以了((

对应的,如果求 xi0 时的最小解,跑最长路即可

建边时注意一下,最长路满足对于有向边 (x,y,z)disydisx+z

所以如果是约束条件 xixj+ck

xjxick

所以建边 (i,j,ck)

仍然按上面的方法建一个超级源点,则每个 xi0

此时求出的就是正整最小解。

附赠 SPFA 最短路 & 判负环

int dis[N], inque[N];
void SPFA(int node) {
memset(inque, 0, sizeof inque);
memset(dis, 0x3f, sizeof dis);
queue<int> q;
q.push(node);
dis[node] = 0;
while (!q.empty()) {
int now = q.front(); q.pop();
inque[now] = 0;
for (int i = h[now]; i; i = a[i].n) {
int j = a[i].t;
if (dis[j] > dis[now] + a[i].v) {
dis[j] = dis[now] + a[i].v;
if (!inque[j])
inque[j] = 1, q.push(j);
}
}
}
}
SPFA(0);

int dis[N], inque[N], cnt[N];
bool SPFA(int node) { // 判负环
memset(inque, 0, sizeof inque);
memset(dis, 0x3f, sizeof dis);
memset(cnt, 0, sizeof cnt);
queue<int> q;
q.push(node);
dis[node] = 0;
cnt[node]++;
while (!q.empty()) {
int now = q.front(); q.pop();
inque[now] = 0;
for (int i = h[now]; i; i = a[i].n) {
int j = a[i].t;
if (dis[j] > dis[now] + a[i].v) {
dis[j] = dis[now] + a[i].v;
cnt[j]++;
if (cnt[j] == n + 1) return false;
if (!inque[j])
inque[j] = 1, q.push(j);
}
}
}
return true;
}
puts(SPFA(0) ? "Yes" : "No");

另外拓扑排序好像也可以判...不过不在本文讨论范围内,而且 SPFA 适用性更广,具体自己可以百度

本文作者:laijinyi

本文链接:https://www.cnblogs.com/laijinyi/p/17605658.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Laijinyi  阅读(33)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起