zoukankan      html  css  js  c++  java
  • 差分约束+tarjin [Poi2012]Festival

      

    问题 D: [Poi2012]Festival

    时间限制: 1 Sec  内存限制: 64 MB

    有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}大小的最大值。

    输入


    第一行三个正整数n, m1, m2 (2<=n<=600, 1<=m1+m2<=100,000)。

    接下来m1行每行两个正整数a,b (1<=a,b<=n),表示第一类限制。

    接下来m2行每行两个正整数c,d (1<=c,d<=n),表示第二类限制。

    输出

    一个正整数,表示集合{Xi}大小的最大值。

    如果无解输出NIE。

    样例输入

    4 2 21 23 41 43 1

    样例输出

    3

    提示

    |X3=1, X1=X4=2, X2=3

    这样答案为3。容易发现没有更大的方案。

        第一眼一看就是差分约束,再一看压根没思路。。

        其实建图还并不是很难,第二个条件只能建单向边(边权0),而第一个明确了大小关系,就该建双向边。

         求出每一个强连通分量,每个强连通分量间是互不影响的(只可能由0边连接)而相连的通分量间可以取最值,一个极大,一个极小,就不会互相影响了。根据刚刚建的边对每个强连通分量跑floyd,找两点间的最大距离,+1就是此强通对答案的贡献。因为两点间最大距离代表这两个点最多距离多远,也就是这个强通里有多少个不同的值了。

         判环:这里得判正环,初始化a[i][i]=0,如果被更新,那一定有正环。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define N 300000
    using namespace std;
    int read()
    {
        int sum=0,f=1;char x=getchar();
        while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
        while(x>='0'&&x<='9'){sum=(sum<<3)+(sum<<1)+x-'0';x=getchar();}
        return sum*f;
    }
    int n,m1,m2,a[605][605],adj[605],e,ans,tot;
    int dfn[605],low[605],cnt,belong[605];
    int zhan[605],inzhan[605],head;
    struct road
    {
        int v,next,l;
    }lu[100000*2+5];
    void add(int u,int v,int l){lu[++e].v=v;lu[e].l=l;lu[e].next=adj[u];adj[u]=e;}
    void tarjin(int x)
    {
        dfn[x]=low[x]=++tot;
        inzhan[x]=1;zhan[++head]=x;
        for(int i=adj[x];i;i=lu[i].next)
        {
            int to=lu[i].v;
            if(!dfn[to])
            {
                tarjin(to);
                low[x]=min(low[x],low[to]);
            }
            else
                if(inzhan[to])
                    low[x]=min(low[x],dfn[to]);    
        }
        if(low[x]==dfn[x])
        {
            int tmp;
            cnt++;
            while(1)
            {
                tmp=zhan[head--];
                belong[tmp]=cnt;
                inzhan[tmp]=0;
                if(tmp==x)break;
            }
        }
    }
    int main()
    {
        memset(a,-2,sizeof(a));
        cin>>n>>m1>>m2;
        int x,y;
        for(int i=1;i<=m1;i++)
        {
            x=read();y=read();
            add(x,y,1);add(y,x,-1);
            a[x][y]=max(a[x][y],1);a[y][x]=max(a[y][x],-1);
        }
        for(int i=1;i<=m2;i++)
        {
            x=read();y=read();
            add(x,y,0);a[x][y]=max(a[x][y],0);
        }
        for(int i=1;i<=n;i++)a[i][i]=0;
        for(int i=1;i<=n;i++)if(!dfn[i])tarjin(i);
        for(int u=1;u<=cnt;u++)
        {   
            for(int k=1;k<=n;k++)
            {
                if(belong[k]!=u)continue;
                for(int i=1;i<=n;i++)
                {
                    if(belong[i]!=u)continue;
                    if(a[i][k]<-10000)continue;
                    for(int j=1;j<=n;j++)
                    {
                        if(belong[j]!=u)continue;
                        if(a[k][j]<-10000)continue;
                        a[i][j]=max(a[i][j],a[i][k]+a[k][j]);
                    }
                }
            }
            int sum=0;
            for(int i=1;i<=n;i++)
            {
                if(belong[i]!=u)continue;
                for(int j=1;j<=n;j++)
                   if(belong[j]==u)sum=max(sum,abs(a[i][j]));
            }
            ans+=sum+1;
        }
        for(int i=1;i<=n;i++)if(a[i][i]!=0){printf("NIE
    ");exit(0);}
        printf("%d
    ",ans);
    }

        

  • 相关阅读:
    Android开发之Sqlite的使用
    ZOJ 3607 Lazier Salesgirl
    ZOJ 3769 Diablo III
    ZOJ 2856 Happy Life
    Ural 1119 Metro
    Ural 1146 Maximum Sum
    HDU 1003 Max Sum
    HDU 1160 FatMouse's Speed
    Ural 1073 Square Country
    Ural 1260 Nudnik Photographer
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7632708.html
Copyright © 2011-2022 走看看