差分约束系统 初见

今天初次学习差分约束系统,很神奇的东西

定义:

如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如xj-xi<=bk(i,j∈[1,n],k∈[1,m]),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。

求解差分约束系统,可以转化成图论的单源最短路径(或最长路径)问题。

其实在一些问题中需求最小值或最大值,同时需要满足一系列的不等式关系,这样就可以用到差分约束系统了,对于求最小值的问题,可以将问题转化为最长路问题;求最大值可以转化为最短路问题。唯一需要注意的就是要找全题中的不等关系,建立正确的边的关系,通常情况下一遍spfa就可以漂亮的解决较为困难的题目。对于大数据也可以很快的出解。

几个小练习:

CODEVS1653 种树2

题目描述 Description

一条街的一边有几座房子。因为环保原因居民想要在路边种些树。路边的地区被分割成块,并被编号为1…n。每个块的大小为一个单位尺寸并最多可种一裸树。每个居民想在门前种些树并指定了三个号码b,e,t。这三个数表示该居民想在b和e之间最少种t棵树。当然,b≤e,居民必须保证在指定地区不能种多于地区被分割成块数的树,即要求T≤ e-b+1。允许居民想种树的各自区域可以交叉。出于资金短缺的原因,环保部门请你求出能够满足所有居民的要求,需要种树的最少数量。

思路:可以将这个题目借助前缀和数组转化到一系列的不等式关系。若用f[i]表示到i所用的树木数,f[e]-f[b]>=t(建一条从b到e的长度为t的边权),在题目中还有一个隐含条件,就是0<=f[i]-f[i-1]<=1,这个隐含关系中可以将f[i]与f[i-1]与0、1建立关系,又多了很多条边。对于<=的情况可以同时乘-1,就转变成了>=,进而用最长路求最小值。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int next[1000000]={0},point[30001]={0},en[1000000]={0},va[1000000]={0},dis[30001]={0},que[1000001]={0};
bool visit[30001]={false};
int main()
{
    int i,j,n,h,b,e,t,tot=0,head,tail,y,x;
    scanf("%d%d",&n,&h);
    for (i=1;i<=h;++i)
    {
        scanf("%d%d%d",&b,&e,&t);
        --b;
        ++tot;
        next[tot]=point[b];
        point[b]=tot;
        en[tot]=e;
        va[tot]=t;
    }
    for (i=1;i<=n;++i)
    {
        ++tot;
        next[tot]=point[i-1];
        point[i-1]=tot;
        en[tot]=i;
        va[tot]=0;
        ++tot;
        next[tot]=point[i];
        point[i]=tot;
        en[tot]=i-1;
        va[tot]=-1;
    }
    memset(dis,128,sizeof(dis));
    dis[0]=0;head=0;tail=1;
    visit[0]=true;que[1]=0;
    do{
        head=head%1000000+1;
        x=que[head];
        visit[x]=false;
        y=point[x];
        while (y!=0)
        {
            if (dis[x]+va[y]>dis[en[y]])
            {
                dis[en[y]]=dis[x]+va[y];
                if (!visit[en[y]])
                {
                    visit[en[y]]=true;
                    tail=tail%1000000+1;
                    que[tail]=en[y];
                }
            }
            y=next[y];
        }
    }while(head!=tail);
    printf("%d\n",dis[n]);
}

CODEVS1768种树3

题目描述 Description

为了绿化乡村,H村积极响应号召,开始种树了。

H村里有n幢房屋,这些屋子的排列顺序很有特点,在一条直线上。于是方便起见,我们给它们标上1~n。树就种在房子前面的空地上。

同时,村民们向村长提出了m个意见,每个意见都是按如下格式:希望第li个房子到第ri个房子的房前至少有ci棵树。

因为每个房屋前的空地面积有限,所以每个房屋前最多只能种ki棵树

村长希望在满足村民全部要求的同时,种最少的树以节约资金。请你帮助村长。

思路:和上一题的大致思路一样,不过有一点不同,0<=f[i]-f[i-1]<=k[i],其他都相同。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int next[5000000]={0},point[500001]={0},en[5000000]={0},va[5000000]={0},k[500001]={0},que[10000001]={0};
long long dis[500001]={0};
bool visit[500001]={false};
int main()
{
    int i,j,n,m,lp,rp,cp,head,tail,tot=0,x,y;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;++i)
      scanf("%d",&k[i]);
    for (i=1;i<=m;++i)
    {
        scanf("%d%d%d",&lp,&rp,&cp);
        --lp;
        ++tot;
        next[tot]=point[lp];
        point[lp]=tot;
        en[tot]=rp;
        va[tot]=cp;
    }
    for (i=1;i<=n;++i)
    {
        ++tot;
        next[tot]=point[i-1];
        point[i-1]=tot;
        en[tot]=i;
        va[tot]=0;
        ++tot;
        next[tot]=point[i];
        point[i]=tot;
        en[tot]=i-1;
        va[tot]=-k[i];
    }
    head=0;tail=1;que[1]=0;
    memset(dis,128,sizeof(dis));
    dis[0]=0;visit[0]=true;
    do{
        head=head%10000000+1;
        x=que[head];
        visit[x]=false;
        y=point[x];
        while(y!=0)
        {
            if (dis[x]+va[y]>dis[en[y]])
            {
                dis[en[y]]=dis[x]+va[y];
                if (!visit[en[y]])
                {
                    visit[en[y]]=true;
                    tail=tail%10000000+1;
                    que[tail]=en[y];
                }
            }
            y=next[y];
        }
    }while(head!=tail);
    printf("%lld\n",dis[n]);
}

poj3159Candies

题目大意:已知a、b两名小朋友间的差值关系(b-a<=c),求n-1的最大值。

思路:又变成了赤裸裸的差分约束系统,a到b的边权为c,搜最短路就可以了。但是这个题的数据卡spfa+queue,从网上学习到spfa可以用栈实现,于是就ac了。(太长知识了,从不知道stack可以实现spfa。。。)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int next[3000000]={0},point[300001]={0},en[3000000]={0},va[3000000]={0},que[1000001]={0};
long long dis[300001]={0};
bool visit[300001]={false};
int main()
{
    int i,j,n,m,tot=0,a,b,c,top=0,x,y;
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;++i)
    {
        scanf("%d%d%d",&a,&b,&c);
        ++tot;
        next[tot]=point[a];
        point[a]=tot;
        en[tot]=b;
        va[tot]=c;
    }
    top=1;que[1]=1;visit[1]=true;
    memset(dis,127,sizeof(dis));dis[1]=0;
    while(top>0)
    {
        x=que[top];
        --top;
        visit[x]=false;
        y=point[x];
        while(y!=0)
        {
            if (dis[en[y]]>dis[x]+va[y])
            {
                dis[en[y]]=dis[x]+va[y];
                if (!visit[en[y]])
                {
                    visit[en[y]]=true;
                    ++top;
                    que[top]=en[y];
                }
            }
            y=next[y];
        }
    }
    printf("%lld\n",dis[n]);
}

在今后的学习中可能还会遇到大于或小于的情况,都可以通过所谓的常数(通常是右侧的部分)+1\-1来转化为>=\<=。

通常情况下最好用spfa,还要判断负环,有的话就不存在。

对于不等式的选取和转化可能是一个难点,但真正能找出题目的本意,正确的套用差分约束系统,才是重点和难点。多加练习吧!!!

时间: 2024-10-02 23:18:11

差分约束系统 初见的相关文章

差分约束系统

差分约束系统是指一系列不等式: $$ X_j - X_i \le C_{ij}(1\le i, j \le n) $$ 当然 i,j 不必取遍 1-n,而且在扩展的状况下,对于每个(i,j),可以由多个 $C_{ij}$,但是我们很容易把它们化成一个不等式. 在求解不等式组之前,我们可以分析一下这个不等式组的性质. 1. 这个不等式组是可以无解的,比如: $$X_1 - X_2 \le -1 \\ X_2 - X_3 \le -1 \\ X_3 - X_1 \le -1$$ 否则三个不等式相加得

UVa 515 - King (差分约束系统 + SPFA求带负权最短路)

下面是差分约束系统的详细介绍,以及解决方法~ 摘抄自 xuezhongfenfei(他好像也是转的....) 差分约束系统 X1 - X2 <= 0 X1 - X5 <= -1 X2 - X5 <= 1 X3 - X1 <= 5 X4 - X1 <= 4 X4 - X3 <= -1 X5 - X3 <= -3 X5 - X4 <= -3 不等式组(1) 全都是两个未知数的差小于等于某个常数(大于等于也可以,因为左右乘以-1就可以化成小于等于).这样的不等式组

ZOJ 3668 Launching the Spacecraft (差分约束系统,最短路)

题目: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3668 题意: 给一个初始值为0的长度为n的区间,给m个约束l,r,a,b,表示从l到r的区间和>=a且<=b,且每个数的范围为-10000~10000,问这个区间的每个数是多少,要求数尽可能大,且序列字典序最大. 方法: 差分约束系统,以前缀和表示一个节点a[i] 建图:根据下面约束条件建图 a[i]-a[i-1]<=10000 a[i-1]-a[i]&l

POJ 2983 Is the Information Reliable?(差分约束系统)

题目地址:POJ 2983 这题刚上来完全不知道跟差分约束系统有什么关系.....后来发现只要判个负环就可以.. 因为假如有冲突的话会形成一个负环.之所以建图加上一个正值一个负值,是因为这样的话,像1 2 4和1 2 3这样的数据就会形成一个负环.这个方法还是很巧妙的...然后对于V的那些不清楚的位置,就会跟P的那些等式联立形成一个不等式,然后在用最短路判环的过程中就用松弛来解决. 代码如下: #include <iostream> #include <cstdio> #inclu

【POJ 1201】 Intervals(差分约束系统)

[POJ 1201] Intervals(差分约束系统) 11 1716的升级版 把原本固定的边权改为不固定. Intervals Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23817   Accepted: 9023 Description You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. Write a p

差分约束系统--详讲

------------差分约束题目请戳:差分约束题集暨报告 总的开说差分约束问题就是给出一系列不等式然后求问某一式子的最大值或者最小值. 差分约束问题具体解释: 比方有这样一组不等式: X1 - X2 <= 0 X1 - X5 <= -1 X2 - X5 <= 1 X3 - X1 <= 5                   不等式组(1) X4 - X1 <= 4 X4 - X3 <= -1 X5 - X3 <= -3 X5 - X4 <= -3 全都是

浅谈差分约束系统——图论不等式的变形

浅谈差分约束系统——图论不等式的变形 ----yangyaojia 版权声明:本篇随笔版权归作者YJSheep(www.cnblogs.com/yangyaojia)所有,转载请保留原地址! 一.定义 如若一个系统由n个变量和m个不等式组成,并且这m个不等式对应的系数矩阵中每一行有且仅有一个1和-1,其它的都为0,这样的系统称为差分约束( difference constraints )系统. 二.分析 简单来说就是给你n个变量,给m个形如x[i]-x[j]≥k①或x[i]-x[j]≤k②.求两

UVA11478 Halum [差分约束系统]

https://vjudge.net/problem/UVA-11478 给定一个有向图,每条边都有一个权值.每次你可以选择一个结点v和一个整数d,把所有以v为终点的边的权值减小d,把所有以v为起点的边的权值增加d,最后让所有边的权值的最小值大于零且尽量大. 该死书上翻译错了 >0不是非负 WA好几次因为这个 考虑每条边的约束,di表示i的halum量 w-dv+du>0 dv-du<w 但求解这个差分约束系统只是让这组不等式成立,最长路和最短路控制的都是单个d的最值而不是最小值最大 那

ACM/ICPC 之 差分约束系统两道(ZOJ2770-POJ1201)

当对问题建立数学模型后,发现其是一个差分方程组,那么问题可以转换为最短路问题,一下分别选用Bellmanford-SPFA解题 ZOJ2770-Burn the Linked Camp //差分约束方程组-转换为最短路问题 //d[v] <= d[u] + dis[u][v] -> d[v] - d[u] <= dis[u][v] //Time:110Ms Memory:12116 #include<iostream> #include<cstring> #inc