详解差分约束系统

来源:互联网 发布:小米手机一直2g网络 编辑:程序博客网 时间:2024/06/16 11:40

什么是差分约束系统?

差分约束系统,是一类关于不等式组的线性规划问题
比如:
给出n个形如 abc的不等式,求一组任意解

一般可以转化为最短路问题求解。

差分约束系统的转化

我们以 XiYiZi为例
观察发现,其实这个不等式与最短路问题中的“三角不等式”相似:
Dist(i)+W(i,j)Dist(j)
Dist(j)Dist(i)W(i,j)

那么是否可以转化为最短路呢?它的实际意义是什么?


三角不等式的意义:
对于求解最短路后的图,选取任意两个有边相连的点,必有Dist(i)+W(i,j)Dist(j)
这意味着:只要存在一条边(i,j),利用最短路算法,必然会得到符合Dist(j)Dist(i)W(i,j)的变量取值
差分约束系统不就是要求符合XiYiZi的变量取值吗!
于是,对于约束条件XiYiZi,我们可以直接建边(Yi,Xi)
然后刷最短路!

就这样解决了!

刷最短路的起点是随意的,因为这不影响任何过程。
刷完最短路只是获得了其中一组解,
题目一般会要求具有某些特征的解,把可行解的所有变量都加上同一个值就可以了

几个小技巧

  1. 前面只阐述了XiYiZi型的问题,其实如果把换成,只需要刷最长路就可以了
  2. 图有可能是不联通的,一般可以建0点,0点向每个点连一条边权为0的边。然后以0为起点
  3. 差分约束系统的无解其实对应着最短路问题的无解(负权回路),SPFA判一下即可
  4. 对于不等式中不带等号的问题,一般答案都是整数,那么就可以通过+1的方法来变成带等号的不等式

经典例题

POJ1201

经典的差分约束系统题型……

首先看到要求最小值,那么显然要刷最长路
xyz 型约束
构造前缀和Si
那么对于一个条件(a,b,c),则有SbSac
值得注意的是,前缀和的单调性 以及 一个位置对答案的贡献最大为1
这两个隐藏条件容易被忽视
SiSi10Si1Si1

然后就没有辣~~

示例程序:

#include<cstdio>#include<cstring>#define nc getchar#define cl(x,y) memset(x,y,sizeof(x))inline int red(){    int res=0,f=1;char ch=nc();    while (ch<'0'||'9'<ch) {if (ch=='-') f=-f;ch=nc();}    while ('0'<=ch&&ch<='9') res=res*10+ch-48,ch=nc();    return res*f;}const int maxn=50005,maxe=150005,INF=0x3f3f3f3f;int n;int tot,lnk[maxn],nxt[maxe],son[maxe],w[maxe];inline void add(int x,int y,int z){    son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;w[tot]=z;}int que[maxn],dst[maxn];bool vis[maxn];void spfa(){    cl(vis,0);cl(dst,192);    int hed=0,til=1;    que[1]=0;dst[0]=0;    while (hed!=til){        int x=que[hed=(hed+1)%maxn];        vis[x]=0;        for (int j=lnk[x];j;j=nxt[j])         if (dst[son[j]]<dst[x]+w[j]){            dst[son[j]]=dst[x]+w[j];            if (!vis[son[j]])             vis[son[j]]=1,que[til=(til+1)%maxn]=son[j];         }    }}int main(){    n=red();    for (int i=0;i<=50000;i++) add(i,i+1,0),add(i+1,i,-1);    for (int i=1,l,r,c;i<=n;i++)     l=red()+1,r=red()+1,c=red(),add(l-1,r,c);    spfa();    printf("%d",dst[50001]);    return 0;}