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

    两天搞了一下差分约束,其实就是一堆不等式进而来求解。

    1.建图并求解

    2.x>y---> x>=y+1 表示从y到x连一条边 边权为1

    3.x<y -----> y>x ------> y>=x+1 表示从x到y连一条边 边权为1

    输出 2

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<ctime>
    #include<algorithm>
    #include<iomanip>
    #include<map>
    #include<string>
    #include<stack>
    #include<queue>
    #include<vector>
    #include<cmath>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int maxn=17000;
    int lin[maxn],e[maxn],ver[maxn],nex[maxn],len=0;
    int vis[maxn],flag=0,dis[maxn],q[maxn],h=0,t=1;;
    void add(int x,int y,int z)
    {
        ver[++len]=y;
        nex[len]=lin[x];
        lin[x]=len;
        e[len]=z;
    }
    int n,m;
    int s1=1002,s2=1003,u[maxn];
    void spfa(int x)
    {
        memset(vis,0,sizeof(vis));
        memset(dis,-10,sizeof(dis));
        memset(q,0,sizeof(q));
        memset(u,0,sizeof(u));
        q[t]=x;dis[x]=0;vis[x]=1;
        while(h<=t)
        {
            int tn=q[++h];vis[tn]=0;
            for(int i=lin[tn];i;i=nex[i])
            {
                int tmp=ver[i];
                if(dis[tn]+e[i]>dis[tmp])
                {
                    dis[tmp]=dis[tn]+e[i];
                    if(vis[tmp]!=1)
                    {
                        q[++t]=tmp;
                        vis[tmp]=1;
                        u[tmp]++;
                    }
                }
                if(u[tmp]>=n+2){printf("NO
    ");flag=1;return;}
            }
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            x=read();y=read();z=read();
            if(z==1)add(x,y,1);
            if(z==-1)add(y,x,1);
            if(z==0)add(x,y,0),add(y,x,0);
        }
        for(int i=1;i<=n;i++)add(s1,i,0),add(i,s2,0);
        spfa(s1);if(flag==1)return 0;
        printf("%d
    ",dis[s2]);
        return 0;
    }
    View Code

    下面一道我调了一中午还超时的差分约束。

    裸的建图然后spfa跑最短(最长路)+判环,下面我跑的的最长路。

    #include<bits/stdc++.h>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<iostream>
    #include<iomanip>
    #include<vector>
    #include<stack>
    #include<map>
    #include<queue>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int maxn=30020;
    int n,m,ans=0,h=0,t=0,flag=0,len=0;
    int lin[maxn<<1],nex[maxn<<1],ver[maxn<<1],e[maxn<<1],u[maxn+10];
    int dis[maxn],vis[maxn+10],s1=maxn,s2=maxn+1,q[maxn<<3];
    void add(int x,int y,int z)
    {
        ver[++len]=y;
        nex[len]=lin[x];
        lin[x]=len;
        e[len]=z;
    }
    void spfa(int x)
    {
        memset(dis,-1,sizeof(dis));
        memset(vis,0,sizeof(vis));
        q[++t]=x;vis[x]=1;dis[x]=0;
        while(h++<t)
        {
            int te=q[h];vis[te]=0;
            for(int i=lin[te];i;i=nex[i])
            {
                int tn=ver[i];
                if(dis[tn]<dis[te]+e[i])
                {
                    dis[tn]=dis[te]+e[i];
                    if(vis[tn]==0){vis[tn]=1;q[++t]=tn;}
                    u[tn]++;
                }
                if(u[tn]>n){flag=1;return;}
            }
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int x,y;
            x=read();y=read();
            add(y,x,1);
        }
        for(int i=1;i<=n;i++)add(s1,i,0),add(i,s2,0);
        spfa(s1);
        if(flag==1)printf("impossible
    ");
        else 
        {
            for(int i=1;i<=n;i++)ans+=dis[i]+100;
            printf("%d
    ",ans);
        }
        return 0;
    }
    ╮(╯▽╰)╭

    上面是超时的一个代码,wa掉一个点因为判环的时候效率不高,n过大,那么如果是一个很大很大的环的话,一定会超时。所以这里选择了双端队列优化,不知道是不是人品的原因,每次双端队列优化都能使让我的超时代码过掉。~高效

    #include<bits/stdc++.h>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<iostream>
    #include<iomanip>
    #include<vector>
    #include<stack>
    #include<map>
    #include<queue>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int maxn=30020;
    int n,m,ans=0,flag=0,len=0;
    int lin[maxn<<1],nex[maxn<<1],ver[maxn<<1],e[maxn<<1],u[maxn+10];
    int dis[maxn],vis[maxn+10],s1=maxn,s2=maxn+1;
    deque<int>q;
    void add(int x,int y,int z)
    {
        ver[++len]=y;
        nex[len]=lin[x];
        lin[x]=len;
        e[len]=z;
    }
    void spfa(int x)
    {
        memset(dis,-1,sizeof(dis));
        memset(vis,0,sizeof(vis));
        q.push_back(x);vis[x]=1;dis[x]=0;
        while(q.size()!=0)
        {
            int te=q.front();vis[te]=0;q.pop_front();
            for(int i=lin[te];i;i=nex[i])
            {
                int tn=ver[i];
                if(dis[tn]<dis[te]+e[i])
                {
                    dis[tn]=dis[te]+e[i];
                    if(vis[tn]==0)
                    {
                        if(q.size()!=0&&dis[ver[i]]<=dis[q.front()])q.push_back(ver[i]);
                        else q.push_front(ver[i]);
                        vis[tn]=1;
                    }
                    u[tn]++;
                }
                if(u[tn]>n){flag=1;return;}
            }
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int x,y;
            x=read();y=read();
            add(y,x,1);
        }
        for(int i=1;i<=n;i++)add(s1,i,0),add(i,s2,0);
        spfa(s1);
        if(flag==1)printf("impossible
    ");
        else 
        {
            for(int i=1;i<=n;i++)ans+=dis[i]+100;
            printf("%d
    ",ans);
        }
        return 0;
    }
    成功

    严密分析一中午发现上面超时原因是判环速度过慢,云学长是采用了拓扑类型的判环,效率会高一点,但其实这道题直接dfs找环加spfa求一个全局最长路即可,但值得注意的是dij+堆是求不出最长路的,dij+堆的原理就是全局最小值不可能被更新,而全局最大值有可能被更新故不能求最长路!

    #include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<stack>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<ctime>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    queue<int>q;
    const int maxn=200200;
    int n,m,s1=maxn-10,flag=0,ans=0;
    int lin[maxn<<1],ver[maxn<<1],nex[maxn<<1],e[maxn<<1],len=0;
    int vis[maxn<<1],dis[maxn<<1];
    void add(int x,int y,int z)
    {
        ver[++len]=y;
        nex[len]=lin[x];
        lin[x]=len;
        e[len]=z;
    }
    void dfs(int x)
    {
        vis[x]=1;
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(vis[tn]==1){flag=1;return;}
            dfs(tn);
        }
        vis[x]=0;
        return;
    }
    void spfa(int x)
    {
        memset(dis,-1,sizeof(dis));
        memset(vis,0,sizeof(vis));
        q.push(x);vis[x]=1;dis[x]=0;
        while(q.size()!=0)
        {
            int te=q.front();vis[te]=0;q.pop();
            for(int i=lin[te];i;i=nex[i])
            {
                int tn=ver[i];
                if(dis[tn]<dis[te]+e[i])
                {
                    dis[tn]=dis[te]+e[i];
                    if(vis[tn]==0)
                    {
                        vis[tn]=1;
                        q.push(tn);
                    }
                }
            }
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int x,y;
            x=read();y=read();
            add(y,x,1);
        }
        for(int i=1;i<=n;i++)add(s1,i,0);
        memset(vis,0,sizeof(vis));dfs(s1);
        if(flag==1){printf("impossible");return 0;}
        spfa(s1);
        for(int i=1;i<=n;i++)ans+=dis[i]+100;
        printf("%d
    ",ans);
        return 0;
    }
    又是一中午

    散落至四方。又或是升起至四方。在无法确认这一事实的浮游感中,彗星耀辉在夜空。彗星裂开,碎片落下。 ——你的名字

  • 相关阅读:
    PAT A1060——string的常见用法详解
    题解-ZJOI2015地震后的幻想乡
    题解-富有物理组的风采
    题解-概率计算器
    题解-CodeForces835F Roads in the Kingdom
    题解-hdu2866 Special Prime
    题解-poj3682King Arthur's Birthday Celebration
    题解-拉格朗日(bzoj3695变种)
    题解-ZeroJudge-c686 高斯符號
    其他-几道物理题
  • 原文地址:https://www.cnblogs.com/chdy/p/9870089.html
Copyright © 2011-2022 走看看