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

    差分约束系统用于解决N元一次不等式组。

    之前感觉学的模模糊糊,现在理得比较清楚后做一个总结。


    1.不等式怎么转换

    先是a-b ≤ c

    对于最短路,有这样的不等式:dis(u) ≤ dis(v) + val(v,u)

    变形得:dis(u) - dis(v) ≤ val(v,u),与a-b ≤ c很相似

    那么对于形如a-b ≤ c的不等式,我们可以从点b向点a连接一条长度为c的边。


     2.跑最长路还是最短路

    这与建图的方式有关。

    a-b ≤ c--->从点b向点a连接一条长度为c的边跑最短路。

     也可以是 --->从点a向点b连接一条长度为-c的边跑最长路。

    如果求的是两个变量差的最大值,那么需要将所有不等式转变成"<=",建图后求最短路。(即求所有满足条件里的最小的)。

    如果求的是两个变量差的最小值,那么需要将所有不等式转化成">=",建图后求最长路。(即要求所有的最小值都满足)。

    而最短路和最长路是可以通过不等式移项相互转化的。


    特殊连边

    我们在建图的时候,并不是只有连和不等式转化的边,还有一些特殊的“隐藏边”。

    可能是某个点有一定的限制。

    比如一个点的位置只能填1或0,处理成前缀和以后就会有0<=sum[i] - sum[i-1]<=1。

    或者说这个点有权值,为了维护这个权值,我们建一个0点,互相连边。

    更多的还要多做不同的题。


     无解情况

    参考

    如果是求解最长路(最小值)的无解情况:

    可考虑先转化成最短路(或者判个正环?)。


    例题

    [USACO05DEC] 布局

    很明显的差分约束,连边最大值跑最短路即可。

    然后要判断无解情况。

    这里要建一个虚拟0点,因为不是点与点之间都有联系,从1跑不一定都跑得到。

    #include<bits/stdc++.h>
    #define LL long long
    #define INF 2100000000
    #define N 1003
    #define M 10003
    #define re register
    using namespace std;
    int read()
    {
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    void print(int x)
    {
        if(x<0)x=-x,putchar('-');
        if(x>9)print(x/10);
        putchar(x%10+'0');
    }
    struct EDGE{
        int nextt,to,val;
    }w[M*3];
    int head[N],tot=0,n;
    int vis[N],dis[N],cnt[N];
    void add(int x,int y,int z)
    {
        tot++;
        w[tot].nextt=head[x];
        w[tot].to=y;
        w[tot].val=z;
        head[x]=tot;
    }
    queue<int>q;
    int spfa(int s)
    {
        while(!q.empty())q.pop();
        for(int i=0;i<=n;++i)dis[i]=INF,vis[i]=0,cnt[i]=0;
        dis[s]=0;vis[s]=1;
        q.push(s);cnt[s]++;
        while(!q.empty())
        {
            int x=q.front();q.pop();
            vis[x]=0;
            for(int i=head[x];i;i=w[i].nextt)
            {
                int v=w[i].to;
                if(dis[v]>dis[x]+w[i].val)
                {
                    dis[v]=dis[x]+w[i].val;
                    if(!vis[v])
                    {
                        vis[v]=1,q.push(v);
                        cnt[v]++;
                        if(cnt[v]>n)return -1;
                    }
                }
            }        
        }
        if(dis[n]==INF)return -2;
        else return dis[n];
    }
    int main()
    {
    //    freopen("a.in","r",stdin);
    //    freopen("a.out","w",stdout);
        n=read();
        int ml=read(),md=read();
        for(re int i=1;i<=ml;++i)
        {
            int a=read();
            int b=read();//sum[b]-sum[a]<=d
            int d=read();//sum[b]<=sum[a]+d
            if(a>b)swap(a,b);
            add(a,b,d);
        }    
        for(re int i=1;i<=md;++i)
        {
            int a=read();
            int b=read();//sum[b]-sum[a]>=d
            int d=read();//sum[b]>=sum[a]+d
            if(a>b)swap(a,b);//sum[a]<=sum[b]-d
            add(b,a,-d);
        }    
        for(int i=2;i<=n;++i)//0<=sum[i]//sum[i-1]<=sum[i]+0
          add(i,i-1,0);
        for(int i=1;i<=n;++i)add(0,i,0);
        if(spfa(0)==-1){printf("-1
    ");return 0;}
        printf("%d
    ",spfa(1));
    }
    /*
    */
    布局

    倍杀测量者

    一开始二分答案mid,考虑check。

    这道题有一个小小的转化。因为是倍数关系,不等式里是乘除而不是加减。

    于是为了转化成加减的形式,我们把倍数取log,因为log函数满足单调性。

    假如我们使得每个人不穿女装,维护这样的不等式,

    如果出现环则无解即有人穿女装,每次有环即可。

    然后因为已知一些选手的分数,我们要去维护这些分数,

    所以建一个虚拟0点,0点的分数为1,这些点与0点的关系也建到图中。

    #include<bits/stdc++.h>
    #define LL long long
    #define INF 2100000000
    #define N 1003
    #define M 10003
    #define re register
    using namespace std;
    int read()
    {
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    void print(int x)
    {
        if(x<0)x=-x,putchar('-');
        if(x>9)print(x/10);
        putchar(x%10+'0');
    }
    struct EDGE{
        int nextt,to;
        double val;
    }w[M*3];
    int head[N],tot=0;
    double dis[N];
    int vis[N],cnt[N];
    int o[N],a[N],b[N],k[N],sco[N],id[N];    
    void add(int x,int y,double z)
    {
        tot++;
        w[tot].nextt=head[x];
        w[tot].to=y;
        w[tot].val=z;
        head[x]=tot;
    }
    int n,s,t;
    queue<int>q;
    bool spfa(int S)
    {
        while(!q.empty())q.pop();
        for(int i=0;i<=n;++i)dis[i]=-INF,vis[i]=0,cnt[i]=0;
        dis[S]=0;vis[S]=1;cnt[S]++;
        q.push(S);
        while(!q.empty())
        {
            int x=q.front();q.pop();
            vis[x]=0;
            for(int i=head[x];i;i=w[i].nextt)
            {
                int v=w[i].to;
                if(dis[v]<dis[x]+w[i].val)
                {
                    dis[v]=dis[x]+w[i].val;
                    if(!vis[v])
                    {
                        vis[v]=1;cnt[v]++;
                        if(cnt[v]>n)return 1;
                        q.push(v);
                    }
                }
            }
        }
        return 0;
    }
    bool check(double mid)
    {
        tot=0;
        memset(head,0,sizeof(head));
        for(int i=1;i<=s;++i)
        {
            if(o[i]==1)//a[i]>b[i]*(k[i]-mid)
              add(b[i],a[i],log2(k[i]-mid));
            else//b[i]/(k[i]+mid)<a[i]
              add(b[i],a[i],-log2(k[i]+mid));
        }
        for(int i=1;i<=t;++i)
        {
            add(0,id[i],log2(sco[i]));
            add(id[i],0,-log2(sco[i]));
        }
        if(spfa(0))return 1;
        return 0;
    }
    int main()
    {
        n=read(),s=read(),t=read();
        for(int i=1;i<=s;++i)
          o[i]=read(),a[i]=read(),b[i]=read(),k[i]=read();
        for(int i=1;i<=t;++i)id[i]=read(),sco[i]=read();
        double l=0,r=10;
        double eps=1e-6;
        while(r-l>eps)
        {
            double mid=(l+r)/2.0;
            if(check(mid))l=mid;
            else r=mid;
        }
        if(l>eps)
        printf("%lf
    ",l);
        else printf("-1
    ");
    }
    倍杀测量者
  • 相关阅读:
    896. Monotonic Array单调数组
    865. Smallest Subtree with all the Deepest Nodes 有最深节点的最小子树
    489. Robot Room Cleaner扫地机器人
    JavaFX
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
  • 原文地址:https://www.cnblogs.com/yyys-/p/11647183.html
Copyright © 2011-2022 走看看