差分约束系统

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

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;
}
又是一中午

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

原文地址:https://www.cnblogs.com/chdy/p/9870089.html