BZOJ2788/POI2012 Festival

来源:互联网 发布:泰达网络登录 编辑:程序博客网 时间:2024/06/05 06:57

Task
有n个正整数X1,X2,…,Xn,再给出m1+m2个限制条件,限制分为两类:
1. 给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb
2. 给出c,d (1<=c,d<=n),要求满足Xc <= Xd
在满足所有限制的条件下,求集合{Xi}大小的最大值。
2<=n<=600, 1<=m1+m2<=100,000.

Solution
1.差分约束:
把Xa+1=Xb转化为Xa+1<=Xb,Xa+1>=Xb,建一条a到b边权为1的边,b到a权值为-1的边.
把Xc<=Xd转化为 Xc-Xd<=0,建一条d到c边权为0的有向边.
建图之后就可以把问题转化为求图中任意两点最短路的最大值.

2.强连通缩点:
图中显然有环,通过强连通转化为DAG,考虑每个强联通分量之间的关系:
假如有一条从a到b的边,说明Xa>=Xb,但两者之间没有具体大小关系,那么我们就能保证存在一组解使得a,b的点权值不重复,那么最终的答案就是每个强连通分量的答案之和.

3.求最短路的最大值:
图中显然可能出现负环,那么就不能用dijkstra算法求最短路.我们可以通过Floyd或者SPFA判断是否有负环,若存在负环,即无解,否则求最短路.

Code

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>using namespace std;const int M=200005;const int N=605;int head[N],scc=0,ec=0,n,m1,m2,dfn[N],low[N],Clock=0,stk[N],top=0,id[N],p[N],sum[N][N];int dis[N][N],inq[N],cnt[N],Q[M*10];struct node{    int to,v,nex;}e[M<<1];inline void rd(int &res){    res=0;char c;    while(c=getchar(),c<48);    do res=(res<<1)+(res<<3)+(c^48);    while(c=getchar(),c>=48);}void ins(int a,int b,int c){    e[ec]=(node){b,c,head[a]};    head[a]=ec++;}void Tarjan(int x){    dfn[x]=low[x]=++Clock;    stk[++top]=x;    inq[x]=1;    for(int i=head[x];~i;i=e[i].nex){        int y=e[i].to;        if(!dfn[y]){            Tarjan(y);            low[x]=min(low[x],low[y]);        }        else if(inq[y])low[x]=min(low[x],dfn[y]);    }    if(low[x]==dfn[x]){        scc++;        while(1){            sum[scc][0]++;            sum[scc][sum[scc][0]]=stk[top];            inq[stk[top]]=0;            id[stk[top--]]=scc;            if(stk[top+1]==x)break;        }    }}int Find_(int k){    int l=0,r=0,i,j,mipath=0;    Q[r++]=p[k];    int s=p[k];    dis[s][s]=0;    while(l<r){        int x=Q[l++];        cnt[x]++;        inq[x]=0;        if(cnt[x]>sum[k][0])return -1;        for(i=head[x];~i;i=e[i].nex){            int y=e[i].to;            if(id[y]!=k)continue;            if(dis[s][y]>dis[s][x]+e[i].v){                dis[s][y]=dis[s][x]+e[i].v;                if(!inq[y]){                    Q[r++]=y;                    inq[y]=1;                }            }        }    }    for(i=1;i<=sum[k][0];i++){        mipath=max(mipath,dis[s][sum[k][i]]);    }    return mipath;}int solve(){    int i,ans=0;    for(i=1;i<=n;i++){        if(!dfn[i])Tarjan(i);    }    for(i=1;i<=scc;i++){        int b=0;        for(int j=1;j<=sum[i][0];j++){            p[i]=sum[i][j];            for(int k=1;k<=sum[i][0];k++){                int y=sum[i][k];                cnt[y]=0,inq[y]=0,dis[p[i]][y]=2e9;            }            int a=Find_(i);            if(a==-1)return -1;            b=max(b,a);         }        ans+=b+1;    }    return ans;}int main(){    memset(head,-1,sizeof(head));    int i,j,a,b,c,k;    rd(n);rd(m1);rd(m2);    for(i=1;i<=m1;i++){        rd(a);rd(b);//a+1=b,->  a+1<=b,a+1>=b ->  a-b<=-1,b-a<=1   a->b 1        ins(a,b,1);        ins(b,a,-1);    }    for(i=1;i<=m2;i++){        rd(a);rd(b);//b>=a  a-b<=0        ins(b,a,0);    }    int res=solve();    if(~res)printf("%d\n",res);    else puts("NIE");    return 0;   }
0 0
原创粉丝点击