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
    ");
    }
    倍杀测量者
  • 相关阅读:
    编辑器1.0
    react native定报预披项目知识点总结
    placeholder中文字添加换行方法
    ios端position为fixed失效的解决办法
    利用fis3构建前端项目工程
    webpack学习记录
    webpack学习记录-认识loader(二)
    webpack学习记录-初步体验(一)
    去抖(节流)
    css布局:左边定宽、右边自适应
  • 原文地址:https://www.cnblogs.com/yyys-/p/11647183.html
Copyright © 2011-2022 走看看