差分约束系统

现在有三个不等式:

begin{cases}
B-A leq k_1 \
C-B leq k_2 \
C-A leq k_3
end{cases}

求出 C − A C-A CA的最大值。
将前两个不等式相加,得到 C − A ≤ k 1 + k 2 C-A \leq k_1+k_2 CAk1+k2
C − A C-A CA需要同时满足

begin{cases}
C-A leq k_1+k_2 \
C-A leq k_3
end{cases}

所以答案为: m i n ( k 1 + k 2 , k 3 ) min(k_1+k_2,k_3) min(k1+k2,k3)
我们考虑用这三个不等式建立一个图, B − A l e q k 1 B-A leq k_1 BAleqk1 表示有一条边 ( A , B ) (A,B) (A,B),边权为 k 1 k_1 k1 C − B l e q k 2 C-B leq k_2 CBleqk2 表示有一条边 ( B , C ) (B,C) (B,C),边权为 k 2 k_2 k2 C − A l e q k 3 C-A leq k_3 CAleqk3 表示有一条边 ( A , C ) (A,C) (A,C),边权为 k 3 k_3 k3,如下图:

答案为 m i n ( k 1 + k 2 , k 3 ) min(k_1+k_2,k_3) min(k1+k2,k3),其实就是找A到C的最短的一条路。

差分约束系统的概念

差分约束系统是一种特殊的 N N N元一次不等式组,包含 N N N个变量 X 1   X N X_1~X_N X1 XN以及 M M M个约束条件,每个约束条件是由两个变量作差构成的,如 X i − X j l e q C k X_i-X_j leq C_k XiXjleqCk , X i − X j > C k X_i-X_j > C_k XiXj>Ck(C_k为常数)等。
差分约束系统要么无解,要么有无数组解。
如果 a 1 , a 2 , a 3 . . . a N {a_1,a_2,a_3...a_N} a1,a2,a3...aN是一组解,那么 a 1 + d , a 2 + d , a 3 + d . . . a N + d {a_1+d,a_2+d,a_3+d...a_N+d} a1+d,a2+d,a3+d...aN+d也是一组解,作差后 d d d恰好消掉。

差分约束系统与最短路

在一个图中,存在一条边 ( u , v ) (u,v) (uv),边权为 W u − > v W_{u->v} Wu>v,源点到点 u , v u,v uv的最短路为 d i s [ u ] , d i s [ v ] dis[u],dis[v] dis[u],dis[v].
那么一定存在不等式: d i s [ v ] l e q d i s [ u ] + W u − > v dis[v] leq dis[u]+W_{u->v} dis[v]leqdis[u]+Wu>v d i s [ v ] dis[v] dis[v]已经是最小值了,从点u经过边 ( u , v ) (u,v) (uv),一定是大于等于 d i s [ v ] dis[v] dis[v]
将不等式移项,可得: d i s [ v ] − d i s [ u ] l e q W u − > v dis[v]-dis[u] leq W_{u->v} dis[v]dis[u]leqWu>v
因此对于不等式 X i − X j l e q W k X_i-X_j leq W_k XiXjleqWk,可以看作存在一条 X i X_i Xi X j X_j Xj的边,边权为 W k W_k Wk。对于不等式组,就可以建立一个图,通过求出源点到其他节点的最短路 d i s dis dis,就是最后的答案。
接下来,我们以下面这个不等式组为例:

begin{cases}
X_3-X_1 leq 5 \
X_4-X_3 leq -3 \
X_4-X_1 leq 4 \
X_5-X_4 leq 0 \
X_2-X_5 leq 1 \
X_1-X_5 leq -1 \
end{cases}

根据不等式组可以建立一个图:

接下来就是求解最短路了。但是,问题来了,哪一个是源点呢?
事实上,任何一个点作为源点都是可以的:
(1)以 X 1 X_1 X1为源点,求解出 d i s [ X 1 ] = 0 , d i s [ X 2 ] = 3 , d i s [ X 3 ] = 5 , d i s [ X 4 ] = 2 , d i s [ X 5 ] = 2 dis[X_1]=0,dis[X_2]=3,dis[X_3]=5,dis[X_4]=2,dis[X_5]=2 dis[X1]=0,dis[X2]=3,dis[X3]=5,dis[X4]=2,dis[X5]=2,带入到不等式组中,发现是满足所有不等式的;
(2)以 X 4 X_4 X4为源点,求解出 d i s [ X 1 ] = − 1 , d i s [ X 2 ] = 1 , d i s [ X 3 ] = 5 , d i s [ X 4 ] = 0 , d i s [ X 5 ] = 0 dis[X_1]=-1,dis[X_2]=1,dis[X_3]=5,dis[X4]=0,dis[X_5]=0 dis[X1]=1,dis[X2]=1,dis[X3]=5,dis[X4]=0,dis[X5]=0,带入到不等式组中,发现是满足所有不等式的;
如果以 X 2 X_2 X2为源点,发现无法到达起点结点,无解。然而,是存在解的,如何处理这种情况呢?
最朴素的做法,就是列举每一个点作为源点,求最短路,但是总的时间复杂度需要乘以 N N N( N N N为结点数目)。
当遇到这种类似的情况,有一个常用的建模思想——超级源点

超级源点

超级源点就是构造一个点,从这个点出发,对每一个点连接一条边权为0的边。
假设存在U到V的最短路:U->…->V,从超级源点出发:超级源点->U->…->V,可以发现,边权为0,所以对最短路没有任何影响,但是这样确保从超级源点出发,能够访问到每一个结点。

其实,也相当于添加了如下不等式组:

begin{cases}
X_1-X_0 leq 0 \
X_2-X_0 leq 0 \
X_3-X_0 leq 0 \
X_4-X_0 leq 0 \
X_5-X_0 leq 0 \
end{cases}

因为 d i s [ X 0 ] = 0 dis[X_0]=0 dis[X0]=0,即添加了限制条件:

begin{cases}
X_1leq 0 \
X_2leq 0 \
X_3leq 0 \
X_4leq 0 \
X_5leq 0 \
end{cases}

X 0 X_0 X0为超级源点,求解出 d i s [ X 1 ] = − 4 , d i s [ X 2 ] = − 2 , d i s [ X 3 ] = 0 , d i s [ X 4 ] = − 3 , d i s [ X 5 ] = − 3 dis[X_1]=-4,dis[X_2]=-2,dis[X_3]=0,dis[X_4]=-3,dis[X_5]=-3 dis[X1]=4,dis[X2]=2,dis[X3]=0,dis[X4]=3,dis[X5]=3
此时,求解出的即是 l e q 0 leq 0 leq0的一组最大解:
因为对于每一个点,如:

begin{cases}
Xleq k_1 \
...\
Xleq 0 \
end{cases}

既要满足 l e q 0 leq 0 leq0,又要满足其他不等式,通过最短路求解出的就是 l e q 0 leq 0 leq0的最大值。

无解

当不等式组建立的图存在负权环,即没有最短路,此时不等式组无解。

解决问题
1. 求解X-Y的最大值

求解X-Y的最大值,不等式组应该为 A − B l e q K A-Bleq K ABleqK K K K为常数)形式,只有leq才能取到最大值。
如果存在geq,那么乘以-1进行转换即可。
求解X-Y的最大值,可以联系开篇的例子,实际上就是求解以X为源点,到Y的最短路。

2. 求解X-Y的最小值

求解X-Y的最大值,不等式组应该为 A − B g e q K A-Bgeq K ABgeqK K K K为常数)形式,只有geq才能取到最大值。
对于最小值,可以求解最长路。
在一个图中,存在一条边 ( u , v ) (u,v) (uv),边权为 W u − > v W_{u->v} Wu>v,源点到点 u , v u,v uv最长路 d [ u ] , d [ v ] d[u],d[v] d[u],d[v].
那么一定存在不等式: d i s [ v ] g e q d i s [ u ] + W u − > v dis[v] geq dis[u]+W_{u->v} dis[v]geqdis[u]+Wu>v d [ v ] d[v] d[v]已经是最大值了,从点u经过边 ( u , v ) (u,v) (uv),一定是小于于等于 d [ v ] d[v] d[v]
求解X-Y的最大值,实际上就是求解以X为源点,到Y的最长路。

3. 求解满足条件的一组解

对于不等式:

begin{cases}
X_3-X_1 leq 5 \
X_4-X_3 leq -3 \
X_4-X_1 leq 4 \
X_5-X_4 leq 0 \
X_2-X_5 leq 1 \
X_1-X_5 leq -1 \
end{cases}

通过添加超级源点,向每个结点连一条边权为0的边,实际上求解出的就是 l e q 0 leq 0 leq0的一组最大解。
例子:【SCOI 2011】糖果
【题目描述】
幼儿园里有 N 个小朋友,lxhgww 老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww 需要满足小朋友们的 K 个要求。幼儿园的糖果总是有限的,lxhgww 想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。
【输入】
输入的第一行是两个整数 N,K。接下来 K 行,表示这些点需要满足的关系,每行 3 个数字,X,A,B。
如果 X=1, 表示第 A 个小朋友分到的糖果必须和第 B 个小朋友分到的糖果一样多;
如果 X=2, 表示第 A 个小朋友分到的糖果必须少于第 B 个小朋友分到的糖果;
如果 X=3, 表示第 A 个小朋友分到的糖果必须不少于第 B 个小朋友分到的糖果;
如果 X=4, 表示第 A 个小朋友分到的糖果必须多于第 B 个小朋友分到的糖果;
如果 X=5, 表示第 A 个小朋友分到的糖果必须不多于第 B 个小朋友分到的糖果;
【输出】
输出一行,表示 lxhgww 老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 −1。
【样例输入】

5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1

【样例输出】

11

【数据范围】
对于 30 30% 30 的数据,保证 $N leq 100 $
对于 100 100% 100 的数据,保证 $N leq 100000 $
对于所有的数据,保证 $K leq 100000,1 leq X leq 5,1 leq A,B leq N $
【题目分析】
(1)如果 X=1, 表示第 A 个小朋友分到的糖果必须和第 B 个小朋友分到的糖果一样多;
一样多,我们可以看作 A − B l e q 0 , B − A g e q 0 A-B leq 0,B-A geq 0 ABleq0BAgeq0,只有A==B,才满足两个不等式。
(2)如果 X=2, 表示第 A 个小朋友分到的糖果必须少于第 B 个小朋友分到的糖果;
看作 A < B + 0 A < B+0 A<B+0,转换为 A l e q B − 1 A leq B-1 AleqB1
(3)如果 X=3, 表示第 A 个小朋友分到的糖果必须不少于第 B 个小朋友分到的糖果;
看作 A g e q B + 0 A geq B+0 AgeqB+0
(4)如果 X=4, 表示第 A 个小朋友分到的糖果必须多于第 B 个小朋友分到的糖果;
看作 A > B + 0 A > B+0 A>B+0,转换为 A g e q B + 1 A geq B+1 AgeqB+1
(5)如果 X=5, 表示第 A 个小朋友分到的糖果必须不多于第 B 个小朋友分到的糖果;
看作 A l e q B + 0 A leq B+0 AleqB+0
同时,题目要求每个小朋友都要分到糖果,即所有分到的糖果数都要 $ geq 1$。即添加不等式组:

begin{cases}
A geq S+1 \
B geq S+1 \
C geq S+1 \
...
end{cases}

将S作为超级源点,向每一个结点连接一条边权为1的边( d [ S ] = 0 d[S]=0 d[S]=0)。此时跑一边最长路,就得到答案了。
那么能不能将不等式转换之后,跑最短路呢?转换为:

begin{cases}
S leq A-1 \
S leq B-1 \
S leq C-1 \
...
end{cases}

这种做法是错误的哦,注意,超级源点是一个假象点,不能有其他结点向超级源点连边。同时,求解的是最少糖果数,最小值,不等式显然要为$ geq $。

#include<bits/stdc++.h>
#define N 100100
#define M 200100
using namespace std;
int n,m,s,vis[N],cnt[N];
int first[N],to[2*M],nex[2*M],t; 
long long dis[N],ans,w[2*M]; 
queue <int> q;
void Add(int u,int v,long long W)
{
    nex[++t]=first[u];
    first[u]=t;
    to[t]=v;
    w[t]=W;
}
void SPFA(int k)
{
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    for(int i=1;i<=n;i++)
        dis[i]=-9999999;
    q.push(k);
    dis[k]=0; 
    vis[k]=1;
    cnt[k]++;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=first[u];i!=-1;i=nex[i])
        {
            int v=to[i];
            if(dis[u]+w[i]>dis[v])
            {
                dis[v]=dis[u]+w[i];
                if(!vis[v])
                {
                    q.push(v);
                    vis[v]=1;
                    cnt[v]++;
                    if(cnt[v]>n) {cout<<-1;exit(0);}
                }
            }
        }
    } 
}
int main()
{
    //freopen("candy6.in","r",stdin);
    memset(first,-1,sizeof(first));
    scanf("%d%d",&n,&m);
    int x,y,z;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        if(x==1)    {Add(y,z,0);Add(z,y,0);}
        if(x==2)    Add(y,z,1);
        if(x==3)    Add(z,y,0);
        if(x==4)    Add(z,y,1);
        if(x==5)    Add(y,z,0);
        if((x==2||x==4)&&y==z) {printf("-1n");return 0;}
    }
    for(int i=n;i>=1;i--)
        Add(0,i,1);
    SPFA(0); 
    for(int i=1;i<=n;i++)
        ans+=dis[i];
    cout<<ans<<endl;
    return 0;
 } 
4.其他情况

( 1 ) 当需要求解X-Y的最大值,但是给出的是形如 A − B g e q K A-Bgeq K ABgeqK K K K为常数)的不等式组。
解决方法:两边同时乘以 − 1 -1 1,转换后得到 B − A l e q − K B-Aleq -K BAleqK
( 2 ) 如果给出的是形如 A − B < K A-B < K AB<K K K K为常数)的不等式组:
解法方法:转换为 A − B l e q K − 1 A-Bleq K-1 ABleqK1

总结

差分约数系统是用来求解不等式组的一组解,应用面比较窄,只能是不等式,通过将不等式建图后求解最长路或最短路。
小于等于求最短路,大于等于求最长路.
超级源点的建模思想需要大家记住,后面也会经常用到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值