あいさか たいがblogAisaka_Taiga的博客
//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

差分约束学习笔记

Toretto·2023-05-06 22:28·139 次阅读

差分约束学习笔记

2023.5.6 写的太烂了重新写

差分约束系统

定义#

差分约束系统是一种特殊的 n 元一次不等式组,它包含 n 个变量 x1,x2,...,xn 以及 m 个约束条件,每一个约束条件都是两个其中的变量做差构成的,形如 xixjck,其中 1i,jn,ij,1km 并且 ck 是常数(可以为正数或非正数)。
------- OI Wiki

通俗一点讲,这类问题都是给定 n 个变量,m 个限制,类似于:

{op1:x1x2=c1op2:x4xn=c2......opm:xnx3=cm

有了这些条件,一般的题目会让你求出一组合法的解,也就是求这 n 个变量的合法的值。

过程#

我们可以建一个超级源点,然后向每一个点连一条边权为 0 的边,然后跑单源最短路;而上面的 m 个限制都可以变形为 xixj+ck,这个东西很容易想到我们在跑最短路的时候的松弛操作里的 dis[v]dis[u]+w,因此我们就可以把每一个变量看作是一个图中的点,对于每一个条件 xixjck,从 ji 连一条边权为 ck 的有向边。

我们在求解的时候一般用 SPFA 来跑,虽然他最坏的时间复杂度是 O(nm) 的,但是我们的差分约束里面要是有负环的话,就说明是无解,再加上有负边权,SPFA 这个已死的算法成了最好的方法,更何况他在一些随机的图中跑的飞快。

最后一个问题,最后转化的式子是 xixj+ck,为什么跑最短路?

但是我觉得,当你建图的时候使用的是 xixjck 形式的方程组建图时,即 ji 连一条权值为 ck 的边,应该选择跑最短路。

如果使用的是 xisjck 形式的方程组来建图时,应该选择跑最长路。

P5960 【模板】差分约束算法#

code:

Copy
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define N 50100 using namespace std; int n,m,cnt,head[N]; queue<int>q; struct SB{int w,v,next;}e[N<<1]; int dis[N],tot[N],vis[N]; inline void add(int u,int v,int w) { e[++cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt; } int SPFA() { q.push(0); vis[0]=1; tot[0]++; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i;i=e[i].next) { int v=e[i].v,w=e[i].w; if(dis[v]>dis[u]+w) { dis[v]=dis[u]+w; q.push(v); vis[v]=1; tot[v]++; if(tot[v]==n+1) return 0; } } } return 1; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) dis[i]=INF; for(int i=1;i<=n;i++) add(0,i,0); for(int i=1;i<=m;i++) { int x,y,z; cin>>x>>y>>z; add(y,x,z); } if(!SPFA()) cout<<"NO"<<endl; else for(int i=1;i<=n;i++) cout<<dis[i]<<" "; return 0; }
posted @   北烛青澜  阅读(139)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
目录