• 差分约束总结


    差分约束,常见的板子类题目,但又不太板子,稍微总结一下:

    (1.)常见的差分约束,将不等式转化为(SPFA)的松弛操作,注意最短路与最长路的区分即可。

    (Eg:[USACO05DEC])布局

    较为板子的板子,如果有(x_i-x_jleq d),建边(j)(i),边权为(d),跑最短路,这是我们最开始的想法,但是这一题告诉我们了一个重要的事情,我们要从(0)(x_i)建一条边权为(0)的边,先从(0)跑一遍(SPFA),再从(1)跑一遍,因为我们不能保证图的连通性……

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int f=1,w=0;char x=0;
        while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
        while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
        return w*f;
    }
    const int N=30010;
    int n,Ml,Md,num_edge,ans;
    int head[N<<1],Cnt[N],dis[N],Vis[N];
    struct Edge{int next,dis,to;} edge[N<<1];
    inline void Add(int from,int to,int dis)
    {
        edge[++num_edge].next=head[from];
        edge[num_edge].dis=dis;
        edge[num_edge].to=to;
        head[from]=num_edge;
    }
    inline void Spfa(int S)
    {
        memset(Cnt,0,sizeof(Cnt));
        memset(Vis,0,sizeof(Vis));
        memset(dis,0x3f3f3f3f,sizeof(dis));
        queue<int> q;q.push(S);dis[S]=0;Vis[S]=1;
        while(!q.empty())
        {
    		int x=q.front();q.pop();Vis[x]=0;
    		for(int i=head[x];i;i=edge[i].next)
    	    	if(dis[edge[i].to]>dis[x]+edge[i].dis)
    	    	{
    				dis[edge[i].to]=dis[x]+edge[i].dis;
    				Cnt[edge[i].to]=Cnt[x]+1;
    				if(Cnt[edge[i].to]>=n) {puts("-1");exit(0);}
    				if(!Vis[edge[i].to]) q.push(edge[i].to),Vis[edge[i].to]=1;
    	    	}   
        }
    }
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
    #endif
        n=read();Ml=read();Md=read();
        for(int i=1;i<=n;i++) Add(0,i,0);
        for(int i=1,u,v,d;i<=Ml;i++)
    		u=read(),v=read(),d=read(),Add(u,v,d);
        for(int i=1,u,v,d;i<=Md;i++)
    		u=read(),v=read(),d=read(),Add(v,u,-d);
        Spfa(0),Spfa(1);
        printf("%d",(dis[n]==0x3f3f3f3f?-2:dis[n]));
    }
    

    (2.)特殊类型的差分约束

    (Eg:[SCOI2008])天平

    我们设(Max[i][j])表示(i,j)的最大可能差值,(Min[i][j])表示(i,j)的最小可能差值,直接跑(Floyd)即可,这类题的特殊之处在于其设的不同,并不是单纯地跑最短路。

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int f=1,w=0;char x=0;
        while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
        while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
        return w*f;
    }
    const int N=70;
    int n,A,B,num_edge,Max[N][N],Min[N][N],ans1,ans2,ans3;
    int main(){
    #ifndef ONLINE_JUDGE
        //freopen("1.in","r",stdin);//Ans=1 4 1;
        freopen("2.in","r",stdin);//Ans=18 12 11;
    #endif
        n=read(),A=read(),B=read();
        for(int i=1;i<=n;i++)
        {
    		char s[N];scanf("%s",s);
    		for(int j=0;j<n;j++)
    	    	if(s[j]=='='||i==j+1) Max[i][j+1]=Min[i][j+1]=0;
    	    	else if(s[j]=='+') Max[i][j+1]=2,Min[i][j+1]=1;
    	    	else if(s[j]=='-') Max[i][j+1]=-1,Min[i][j+1]=-2;
    	    	else Max[i][j+1]=2,Min[i][j+1]=-2;
        }
        for(int k=1;k<=n;k++)
    	for(int i=1;i<=n;i++)
    	    if(i!=k)
    			for(int j=1;j<=n;j++)
    		    	if(j!=k&&i!=j)
    		    	{
    					Max[i][j]=min(Max[i][j],Max[i][k]+Max[k][j]);
    					Min[i][j]=max(Min[i][j],Min[i][k]+Min[k][j]);
    		    	}
        for(int C=1;C<=n;C++)
    		if(A!=C&&B!=C)
    	    	for(int D=1;D<C;D++)
    			if(A!=D&&B!=D)
    			{
    		    	ans1+=(Min[A][C]>Max[D][B])||(Min[A][D]>Max[C][B]);
    		    	ans3+=(Min[C][A]>Max[B][D])||(Min[D][A]>Max[B][C]);
    		    	ans2+=((Min[A][C]==Max[A][C])&&(Min[D][B]==Max[D][B])&&(Min[A][C]==Min[D][B]))||((Min[A][D]==Max[A][D])&&(Min[C][B]==Max[C][B])&&(Min[A][D]==Min[C][B]));
    			}
        printf("%d %d %d",ans1,ans2,ans3);
    }
    

    (Eg:[1007])倍杀测量者

    这一题题意需要简化后才能出来思路,先看到找答案,显然二分,然后考虑判断答案是否合法。

    显然我们要把图重建一遍,但是所谓的“女装(Flag)“该怎么办?考虑一个人在什么情况下要女装,当(i)立了一个(Flag)曰:“我没(k)倍杀选手(j),我就女装时”,如果他不满足(x_i>x_j*k)时就会被强迫女装。

    同理,当(i)立了”选手Y把我kkk倍杀,我就女装“,如果他不满足(x_i>x_j*frac{1}{k})时就会被强迫女装。

    对于选手(i)固定的分数(x),我们建边(0)(i),边权为(x),建边(i)(0),边权为(frac{1}{x})

    此时我们将最短路求和转化为最短路求积即可,如果要取模,就取(log),但这一题并不要。(我记得某个毒瘤学长就出了这样的一道题……)

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int f=1,w=0;char x=0;
        while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
        while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
        return w*f;
    }
    const int N=30010;
    const double Eps=1e-8;
    double dis[N],X[N];
    int n,Fls,Cos,num_edge;
    int head[N<<1],Cnt[N],Vis[N],C[N];
    struct Flag{int typ,A,B;double k;} Oier[N];
    struct Edge{int next,to;double dis;} edge[N<<1];
    inline void Add(int from,int to,double dis)
    {
        edge[++num_edge].next=head[from];
        edge[num_edge].dis=dis;
        edge[num_edge].to=to;
        head[from]=num_edge;
    }
    inline bool Spfa(int S)
    {
        memset(Cnt,0,sizeof(Cnt));
        memset(Vis,0,sizeof(Vis));
        memset(dis,0,sizeof(dis));
        queue<int> q;q.push(S);Vis[S]=1;dis[S]=1;
        while(!q.empty())
        {
    	int x=q.front();q.pop();Vis[x]=0;
    	for(int i=head[x];i;i=edge[i].next)
    	    if(dis[edge[i].to]<dis[x]*edge[i].dis)
    	    {
    		dis[edge[i].to]=dis[x]*edge[i].dis;
    		if(!Vis[edge[i].to])
    		{
    		    q.push(edge[i].to),Vis[edge[i].to]=1;
    		    Cnt[edge[i].to]=Cnt[x]+1;
    		    if(Cnt[edge[i].to]>n+1) return 1;
    		}
    	    }
        }
        return 0;
    }
    inline bool Check(double T)
    {
        num_edge=0;memset(head,0,sizeof(head));
        for(int i=1;i<=Cos;i++)
    	Add(0,C[i],X[i]),Add(C[i],0,1.0/X[i]);
        for(int i=1;i<=Fls;i++)
    	if(Oier[i].typ==1) Add(Oier[i].B,Oier[i].A,Oier[i].k-T);
    	else Add(Oier[i].B,Oier[i].A,1.0/(Oier[i].k+T));
        return Spfa(0);
    }
    int main(){
    #ifndef ONLINE_JUDGE
        //freopen("1.in","r",stdin);//Ans=-1;
        freopen("2.in","r",stdin);//Ans=3.9999993984;
    #endif
        double l=0,r=0,ans=-1;
        n=read();Fls=read();Cos=read();
        for(int i=1;i<=Fls;i++)
        {
    	Oier[i].typ=read(),Oier[i].A=read();
    	Oier[i].B=read(),Oier[i].k=(double)read();
    	r=max(Oier[i].k,r);
        }
        //cout<<l<<' '<<r;
        for(int i=1;i<=Cos;i++) C[i]=read(),X[i]=(double)read();
        while(r-l>Eps)
        {
    	double mid=(l+r)/2;
    	if(Check(mid)) l=ans=mid;
    	else r=mid;
        }
        ans==-1?puts("-1"):printf("%.10lf
    ",ans);
    }
    
  • 相关阅读:
    大型网站应用中MySQL的架构演变史
    SRM 585 DIV2
    TC 配置插件
    Java中含有静态成员的的初始化顺序
    java 23种设计模式,一般情况下,常用的有哪些? 转载
    Java中的正则表达式
    C++ 中的关于输出的设置于
    C++实现可变参数列表
    Java中的组合与聚合
    pku 2284 That Nice Euler Circuit
  • 原文地址:https://www.cnblogs.com/wo-shi-zhen-de-cai/p/11412611.html
Copyright © 2020-2023  润新知