详解差分约束系统

本文详细介绍了差分约束系统,将其转化为最短路问题求解,并分享了相关技巧和经典例题。通过理解差分约束系统与最短路问题的关系,可以有效地解决这类问题。文中还提到了如何处理不等式类型的变化,以及如何处理不联通的图和无解的情况。
摘要由CSDN通过智能技术生成

什么是差分约束系统?

差分约束系统,是一类关于不等式组的线性规划问题
比如:
给出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
这两个隐藏条件容易被忽视
SiSi10 Si1Si1

然后就没有辣~~

示例程序:

#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;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值