zoukankan      html  css  js  c++  java
  • 差分约束系统

     

    一、算法简介

      差分约束系统是一种特殊的N元一次不等式组,它包含N个变量,X1~Xn以及m个约束条件,每一个约束条件都是由两个变量作差构成的,形如Xi-Xj≤Ck,其中Ck是常数,1≤i,j≤N,1≤k≤M,解决的问题是求一组解,X1=a1,X2=a2~~~Xn=an,使得所有的约束条件都得到满足。

      差分约束系统的每一个约束条件Xi-Xj≤Ck可以变形为最短路中的三角不等式,Xi≤Xj+Ck,因此,可以把每一个变量Xi看作有向图中的一个结点i,对于每一个约束条件Xi-Xj≤Ck,为从结点j想结点i连一条长度为Ck的有向边

    二、例题

      UVA1723 Intervals

      此题是差分约束的裸题,但我之前也不知道差分约束系统是什么。

      定义:差分约束系统是一种特殊的N元一次不等式,包含N个变量及M个约束条件,每个约束条件由两个变量作差构成,形如Xi-Xj>=Ck,Ck是常数,1<=i,j<=N,1<=k<=M。如

      X1-X0>=2
      X2-X1>=3
      X3-X2>=2
      X3-X0>=6

      通过消元可得到X3-X0的最小值为7。假若我们从0->1建一条权值为2的边,从1->2建一条权值为3的边,以此类推。从0到3跑一遍SPFA求最长路,发现也为7。

      这不是个巧合,因为求最长路时,SPFA的松弛操作后,dis[v]>=dis[u]+g[i].w,与不等式Xi>=Xj+Ck性质一样,所以SPFA可以求出最小值,又因为不等式同大取大,所以要求出最长路。所以SPFA死了吗?

      最后,一定要注意输出,每个答案空一行,最后一个答案最后要输出换行。

      本题就是从0-50000选出最少的数,使每个区间至少有c个数被选,这是求最小值,所以我们待会要将所有的不等式转换成">="的形式 我们用数组d[i]表示0-i之间至少要选多少个数,所以对于每一个约束条件,可以看成d[b_i]-d[a_i-1]>=c_id[bi]d[ai1]>=ci

      d[bi]>=ci+d[ai1]

      因此我们在a[i-1]和b[i]之间建一条长度为c[i]的边

      上述建边过程只是题干中给出的条件,我们还要找出题目中的隐藏条件(隐藏条件视题目而为,有则加)。

      因为d[i]表示的是0-i之间要选的最小个数,所以d[i]一定要大于d[i-1];又因为每个数只能选一次,所以d[i]-d[i-1]要么为0,要么为1;

      由上述两个条件,我们对应出两个不等式d_i-d_{i-1}>=0didi1>=0d_{i-1}-d_{i}>=-1di1di>=1

      所以我们在i-1和i之间连长度为0的有向边,在i和i-1之间连长度为-1的有向边

      因为i的范围是0-50000所以i-1会变成负数,我们都知道,若数组的下标为负,程序会运行错误,所以我们不妨给所有的变量加1,这样就不会出现负下标了,所以上述加边过程可简述为

        1---->在a[i]和b[i]+1之间连一条长度为c[i]的有向边
    
        2---->在i和i+1之间连一条长度为0的有向边
    
        3---->在i+1和i之间连一条长度为-1的有向边

      接着,设d[0]为1,以0为起点求单元最长路

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    int t,n,head[500005],tot,ma,dis[500005];
    bool vis[500005];
    struct node{
        int u,v,next,w;
    }g[5000005];
    inline int rea(){//快读
        int s=0,g=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                g=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            s=(s<<3)+(s<<1)+(ch^48);
            ch=getchar();
        }
        return s*g;
    }
    inline void add(int u,int v,int w){//建图
        g[++tot].u=u;
        g[tot].v=v;
        g[tot].w=w;
        g[tot].next=head[u];
        head[u]=tot;
    }
    inline void spfa(){//SPFA求最长路,即可得出最小值
        queue<int>q;
        q.push(0);
        vis[0]=true;
        dis[0]=0;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=false;
            for(int i=head[u];i;i=g[i].next){
                int v=g[i].v;
                if(dis[v]<dis[u]+g[i].w){
                    dis[v]=dis[u]+g[i].w;
                    if(!vis[v]){
                        vis[v]=true;
                        q.push(v);
                    }
                }
            }
        }
    }
    int main(){
        t=rea();
        while(t--){
            memset(head,0,sizeof(head));
            memset(dis,-0x3f,sizeof(dis));
            tot=0;
            n=rea();
            for(int i=1;i<=n;i=-~i){
                int a=rea(),b=rea(),c=rea();
                add(a,b+1,c);//因为前缀和中,Sb-S(a-1)>=c,然而a-1要大于等于0,a有可能是0,所以我们加一
                ma=max(ma,b+1);
            }
            for(int i=1;i<=ma;i=-~i){
                add(i-1,i,0);
                add(i,i-1,-1);//Si-S(i-1)>=0,S(i-1)-Si>=-1
            }
            spfa();
            printf("%d
    ",dis[ma]);
            if(t)
                printf("
    ");//注意输出!!!
        }
        return 0;
    }
     

    三、相关文章链接

      https://blog.csdn.net/dragon60066/article/details/80245797

  • 相关阅读:
    几个新角色:数据科学家、数据分析师、数据(算法)工程师
    人类投资经理再也无法击败电脑的时代终将到来了...
    Action Results in Web API 2
    Multiple actions were found that match the request in Web Api
    Routing in ASP.NET Web API
    how to create an asp.net web api project in visual studio 2017
    网站漏洞扫描工具
    How does asp.net web api work?
    asp.net web api history and how does it work?
    What is the difference between a web API and a web service?
  • 原文地址:https://www.cnblogs.com/SeanOcean/p/11246604.html
Copyright © 2011-2022 走看看