差分约束

差分约束

什么是差分约束?

差分约束系统(system of difference constraints),是求解关于一组变数的特殊不等式组之方法。如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如xj-xi<=bk(i,j∈[1,n],k∈[1,m]),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。
(以上转自某博客)
其实。。差分约束在某种程度上来说像是一个转换的工具,解释请看下文

差分约束的核心思路

差分约束大部分时候像是把一个问题转换为几个不等式,并转换为最短路来求解
如何转换为最短路?
我们用到了三角不等式。
B - A <= c (1)

C - B <= a (2)

C - A <= b (3)

如果要求C-A的最大值,可以知道max(C-A)= min(b,a+c)
如:对于一个 xi-xj<=an
则有一条i到j的边,权值为an。以此来建图。
有些时候不等式不是现成的,这是需要对现有的不等式进行加减。如
x3-x2<=1
x2-x1<=3
可以将两式相加,得到新的不等式
(三角不等式也被经常用来做最短路的松弛操作)

最长路&最短路

最长路

最长路就是第一个点到第n个点的最短路
证明可以另查(实际上我也不会证)
但是你可以这么理解
对于一个式子a-b,当a一定,b越小,这个式子的值越大

最短路

最短路其实和最长路相反,是第一个点到第n个点的最长路
证明方法同上理(就是b大了,a-b的值就小了)

判断有没有解

就是用spfa来判环
(据说优化后的bellman-ford也可以)

干货版(转自其他博客)

上面的是我通俗化过的,但是如果你想看看最正式的解释也是可以的
下面有一个超级源点,其实就是在处理特例
差分约束系统的解法如下:

1、 根据条件把题意通过变量组表达出来得到不等式组,注意要发掘出隐含的不等式,比如说前后两个变量之间隐含的不等式关系。

2、 进行建图:

首先根据题目的要求进行不等式组的标准化。

(1)、如果要求取最小值,那么求出最长路,那么将不等式全部化成xi – xj >= k的形式,这样建立j->i的边,权值为k的边,如果不等式组中有xi – xj > k,因为一般题目都是对整形变量的约束,化为xi – xj >= k+1即可,如果xi – xj = k呢,那么可以变为如下两个:xi – xj >= k, xi – xj <= k,进一步变为xj – xi >= -k,建立两条边即可。

(2)、如果求取的是最大值,那么求取最短路,将不等式全部化成xi – xj <= k的形式, 这样建立j->i的边,权值为k的边,如果像上面的两种情况,那么同样地标准化就行了。

(3)、如果要判断差分约束系统是否存在解,一般都是判断环,选择求最短路或者最长路求解都行,只是不等式标准化时候不同,判环地话,用spfa即可,n个点中如果同一个点入队超过n次,那么即存在环。

值得注意的一点是:建立的图可能不联通,我们只需要加入一个超级源点,比如说求取最长路时图不联通的话,我们只需要加入一个点S,对其他的每个点建立一条权值为0的边图就联通了,然后从S点开始进行spfa判环。最短路类似。

3、 建好图之后直接spfa或bellman-ford求解,不能用dijstra算法,因为一般存在负边,注意初始化的问题。

程序实现

其实你可以去看看poj的1201-intervals。这道题被许多博客当做范例来讲,感觉也确实像是一个模版题。可以试试。
附上不是我的标程一个(主要是poj最近打不开)

#include<cstdio>  
#include<cstring>  
#include<queue>  
#include<algorithm>  
using namespace std;  
const int maxn= 50000+10;  
const int maxm=500000+10;  
#define INF 1e9  
  
struct Edge  
{  
    int from,to,dist;  
    Edge(){}  
    Edge(int f,int t,int d):from(f),to(t),dist(d){}  
};  
  
struct SPFA  
{  
    int n,m;  
    int head[maxn],next[maxm];  
    Edge edges[maxm];  
    int d[maxn];  
    bool inq[maxn];  
  
    void init()  
    {  
        m=0;  
        memset(head,-1,sizeof(head));  
    }  
  
    void AddEdge(int from,int to,int dist)  
    {  
        edges[m]=Edge(from,to,dist);  
        next[m]=head[from];  
        head[from]=m++;  
    }  
  
    int spfa()  
    {  
        memset(inq,0,sizeof(inq));  
        for(int i=0;i<n;i++) d[i]= i==0?0:INF;  
        queue<int> Q;  
        Q.push(0);  
  
        while(!Q.empty())  
        {  
            int u=Q.front(); Q.pop();  
            inq[u]=false;  
  
            for(int i=head[u];i!=-1;i=next[i])  
            {  
                Edge &e=edges[i];  
                if(d[e.to]>d[u]+e.dist)  
                {  
                    d[e.to]=d[u]+e.dist;  
                    if(!inq[e.to])  
                    {  
                        inq[e.to]=true;  
                        Q.push(e.to);  
                    }  
                }  
            }  
        }  
        return d[n-1]-d[9];  
    }  
}SP;  
  
int main()  
{  
    int n,max_v=-1;  
    scanf("%d",&n);  
    SP.init();  
    while(n--)  
    {  
        int a,b,c;  
        scanf("%d%d%d",&a,&b,&c);  
        b+=10,a+=10;//所有值都加10了,以免a-1成为-1  
        max_v=max(max_v,b);  
        SP.AddEdge(b,a-1,-c);  
    }  
    for(int i=10;i<=max_v;i++)//从该循环可看出,本差分约束的点编号为:[9,max_v](未包含超级源0号点)  
    {  
        SP.AddEdge(i,i-1,0);  
        SP.AddEdge(i-1,i,1);  
        SP.AddEdge(0,i,0);  
    }  
    SP.AddEdge(0,9,0);  
    SP.n=max_v+1;  
    printf("%d\n",SP.spfa());//注意最终结果是d[max_v]-d[9]的值,而不是d[max_v]的单独值  
    return 0;  
}

思路还是一样的,只是感觉这个代码写的。。不是很通俗易懂

差分约束就到这里了,我觉得它更像一个工具,有种数形结合百般好的感觉

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 【概述】 SVM训练分类器的方法是寻找到超平面,使正负样本在超平面的两侧(分类正确性即“分得开”),且样本到超平面...
    sealaes阅读 11,046评论 0 7
  • 参见贪心算法——最短路径Dijkstra算法参见动态规划 目录 0.最短路径问题0.1 最短路径问题描述 0.1....
    王侦阅读 4,800评论 1 9
  • 本章涉及到的知识点清单:1、决策面方程2、函数间隔和几何间隔3、不等式约束条件4、SVM最优化模型的数学描述(凸二...
    PrivateEye_zzy阅读 13,215评论 3 10