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

    差分约束系统
    差分约束系统是求解关于一组变量的特殊不等式组的方法,系统由(n)个变量和(m)个不等式组成,其中每个不等式的形式为

    [x_i-x_jleq b_k(i,jin [1,n],kin (1,m) ]

    或者

    [x_i-x_jgeq b_k(i,jin [1,n],kin (1,m) ]

    分别对应两数差的最大值(最短路)和最小值(最长路)
    差分约束系统的求解方法
    差分约束系统可以转化为图论的最短路或者最长路解决
    由于在最短路算法的松弛过程中,(dis[v]leq dis[u]+w(u,v)),也就是(dis[v]-dis[u]leq w(u,v)),与差分约束系统中不等式的形式相似,所以对于每个不等式,从(x_j)(x_i)连接一条边。计算(x_n-x_1)的最大值,等价于计算从(x_1)(x_n)的最短路
    类似地,计算(x_n-x_1)的最小值,等价于计算从(x_1)(x_n)的最长路
    所以首先可以根据求解的是最大值还是最小值,改变不等号的方向,使得不等式组中所有不等号的方向一致。最小值对应的不等号为(leq),最大值对应的不等号为(geq)
    建图之后不一定存在最短路或者最长路,也就是差分约束系统不一定有解,判断是否有解等价于判断图中是否存在负环((Bellman-Ford)或者(SPFA)
    相关题目
    hdu3440 House Man 求解最大值
    给出一列数作为房屋高度,其中所有的高度值都不相同,按照高度从低到高的顺序逐个在房顶上跳,每个房屋被跳一次,每次跳的两个房屋之间的距离不超过(d)。同一个位置最多只有一个房屋,在不改变原来房屋排列顺序的情况下安排所有房屋之间的距离,计算最低的房屋和最高的房屋之间距离的最大值。

    设高度为(h)的房屋在给定的排列中的顺序为(a_h),按照高度排序之后第(i)个房屋的高度为(b_i)。由于高度相邻的两个房屋之间的距离不超过(d),所以有(max(a_{b_i},a_{b_{i-1}})-min(a_{b_i},a_{b_{i-1}})leq d)
    由于同一个位置最多只有一个房屋,所以有(a_i-a_{i-1}geq 1),也就是(a_{i-1}-a_ileq -1)
    所以共有两种类型的不等式:

    [left{egin{matrix}max(a_{b_i},a_{b_{i-1}})-min(a_{b_i},a_{b_{i-1}})leq d\ a_{i-1}-a_ileq -1end{matrix} ight.]

    由于求解的是最大值,所以建图通过(spfa)算法计算从(min(a_{b_1},a_{b_n}))(max(a_{b_1},a_{b_n}))的最短路

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #include<cstring>
    #include<string>
    #include<sstream>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #define LL long long
    #define PII pair<int,int>
    #define PLL pair<LL,LL>
    #define pi acos(-1.0)
    #define eps 1e-6
    #define lowbit(x) x&(-x)
    using namespace std;
    
    const int maxn=1010;
    int T,n,d,head[maxn],to[4*maxn],nxt[4*maxn],weight[4*maxn],cnt;
    int inq[maxn],k[maxn];
    LL a[maxn],b[maxn],dis[maxn];
    map<LL,int> mp;
    
    void add(int u,int v,int w){
        to[cnt]=v;
        weight[cnt]=w;
        nxt[cnt]=head[u];
        head[u]=cnt++;
    }
    
    bool spfa(int s){
        for(int i=1;i<=n;i++){
            dis[i]=(i==s)?0:1e18;
            inq[i]=(i==s)?1:0;
            k[i]=(i==s)?1:0;
        }
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int p=q.front();
            q.pop();
            inq[p]=0;
            for(int i=head[p];~i;i=nxt[i]){
                int v=to[i],w=weight[i];
                if(dis[v]>dis[p]+w){
                    dis[v]=dis[p]+w;
                    k[v]++;
                    if(k[v]>=n) return true;
                    if(!inq[v]){
                        inq[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return false;
    }
    
    int main(){
        scanf("%d",&T);
        for(int cas=1;cas<=T;cas++){
            scanf("%d %d",&n,&d);
            mp.clear();
            for(int i=1;i<=n;i++){
                scanf("%lld",&a[i]);
                mp[a[i]]=i;
                b[i]=a[i];
            }
            sort(b+1,b+1+n);
            memset(head,-1,sizeof(head));
            cnt=0;
            for(int i=2;i<=n;i++){
                int u=mp[b[i-1]];
                int v=mp[b[i]];
                add(min(u,v),max(u,v),d);
            }
            for(int i=2;i<=n;i++){
                add(i,i-1,-1);
            }
            printf("Case %d: ",cas);
            int mini=mp[b[1]];
            int maxi=mp[b[n]];
            if(!spfa(min(mini,maxi))){
                printf("%lld
    ",dis[max(mini,maxi)]);
            }
            else printf("-1
    ");
        }
        return 0;
    }
    

    hdu1384 Intervals 求解最小值
    给出(n)个区间,每个区间为([a_i,b_i]),选取一些数,使得区间(i)中的数的个数不少于(c_i),计算选取的数的个数的最小值

    (S_i)表示([1,i])中选取的数的个数的最小值,则对于每一个区间([a_i,b_i]),有不等式(S_{b_i}-S_{a_i-1}geq c_i)
    同时存在不等式(0leq S_i-S_{i-1}leq 1),拆分成两个不等式(S_igeq S_{i-1}+0)(S_{i-1}geq S_i-1)
    所以共有三种不等式:

    [left{egin{matrix}S_{b_i}-S_{a_i-1}geq c_i\ S_igeq S_{i-1}+0\ S_{i-1}geq S_i-1end{matrix} ight.]

    由于求解的是最小值,所以建图通过(spfa)算法计算从(S_{mini})(S_{maxi})的最长路

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #include<cstring>
    #include<string>
    #include<sstream>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #define LL long long
    #define PII pair<int,int>
    #define PLL pair<LL,LL>
    #define pi acos(-1.0)
    #define eps 1e-6
    #define lowbit(x) x&(-x)
    using namespace std;
    
    const int maxn=50010,inf=0x3f3f3f3f;
    int n,head[maxn],nxt[4*maxn],to[4*maxn],weight[4*maxn],cnt,inq[maxn];
    LL dis[maxn];
    queue<int> q;
    
    void add(int u,int v,int w){
        to[cnt]=v;
        weight[cnt]=w;
        nxt[cnt]=head[u];
        head[u]=cnt++;
    }
    
    void spfa(int mini,int maxi){
        for(int i=mini+1;i<=maxi;i++){
            dis[i]=-1e18;
            inq[i]=0;
        }
        dis[mini]=0;
        inq[mini]=1;
        q.push(mini);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            inq[u]=0;
            for(int i=head[u];~i;i=nxt[i]){
                int v=to[i],w=weight[i];
                if(dis[v]<dis[u]+w){
                    dis[v]=dis[u]+w;
                    if(!inq[v]){
                        q.push(v);
                        inq[v]=1;
                    }
                }
            }
        }
    }
    
    int main(){
        while(~scanf("%d",&n)){
            memset(head,-1,sizeof(head));
            cnt=0;
            int mini=inf,maxi=-1;
            for(int i=1;i<=n;i++){
                int u,v,w;
                scanf("%d %d %d",&u,&v,&w);
                add(u-1,v,w);
                mini=min(mini,u-1);
                maxi=max(maxi,v);
            }
            for(int i=mini+1;i<=maxi;i++){
                add(i-1,i,0);
                add(i,i-1,-1);
            }
            spfa(mini,maxi);
            printf("%lld
    ",dis[maxi]);
        }
        return 0;
    }
    
  • 相关阅读:
    logging模块-logging.basicConfig、logger.setLevel、handler.setLevel优先级
    Python标准模块--logging(转载)
    第三节,入门知识和windows系统安装python环境
    第二节windows系统下Xshell 5软件远程访问虚拟机 Linux系统
    第一节windows系统安装虚拟机VMware 软件
    数学数列
    java String
    linux eclipse 报错过时的方法
    java.util.Random 类
    java uitl
  • 原文地址:https://www.cnblogs.com/fxq1304/p/13547901.html
Copyright © 2011-2022 走看看