zoukankan      html  css  js  c++  java
  • [Poi2012]Festival

     

    转载请注明出处:

    http://www.cnblogs.com/hzoi-wangxh/p/7738628.html 

    [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。容易发现没有更大的方案。

    solution

        首先想到差分约束。对于限制2,Xc<=Xd,我们可以把它导成Xc-Xd<=0,由d向c建一条边权为0的边。对于限制1,我们可以转换成Xa+1<=Xb Xa+1>=Xb,然后再导成Xa-Xb<=-1 Xb-Xa<=1,由b向a建一条边权为-1的边,由a向b建一条边权为1的边。注意如果之前已经在两点之间建过边,边权取最小值。

        然后我们开始在图上跑。由于需要满足条件,我们跑最短路。先用tarjan缩点,在每一个环里跑两点之间距离的最小值。如果跑出来发现dis[i][i]不为0,说明不能满足条件。如果能满足,取每个环里两点之间距离绝对值的最大值,相加即为集合最大的大小。

    附上代码

     

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    struct tree{
        int u,v,next,d;
    }l[301000];
    int n,m1,m2,lian[605],e,dis[605][605];
    int low[605],dfn[605],num,fa[605],cnt,head,st[605];
    bool pd[605];
    void bian(int,int,int);
    void tarjan(int);
    int mmin(int x,int y)
    {
        if(x>y) return y;
        return x;
    }
    int mmax(int x,int y)
    {
        if(x>y) return x;
        return y;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        scanf("%d%d%d",&n,&m1,&m2);
        memset(dis,30,sizeof(dis));
        for(int i=1;i<=m1;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            bian(y,x,-1);
            bian(x,y,1);
            dis[y][x]=mmin(dis[y][x],-1);
            dis[x][y]=mmin(dis[x][y],1);
        }
        for(int i=1;i<=m2;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            bian(y,x,0);
            dis[y][x]=mmin(dis[y][x],0);
        }
        for(int i=1;i<=n;i++)
            if(dfn[i]==0)
                tarjan(i);
        for(int i=1;i<=n;i++)
            dis[i][i]=0;
        for(int i=1;i<=cnt;i++)
            for(int j=1;j<=n;j++)
            {
                if(fa[j]!=i) continue;
                for(int k=1;k<=n;k++)
                {
                    if(fa[k]!=i) continue;
                    for(int l=1;l<=n;l++)
                    {
                        if(fa[l]!=i) continue;
                        dis[k][l]=mmin(dis[k][l],dis[k][j]+dis[j][l]);
                    }
                }
            }
        bool cun=0;
        for(int i=1;i<=n;i++)
            if(dis[i][i]!=0)
            {
                cun=1;break;
            }
        if(cun==1)
        {
            printf("NIE");
            return 0;
        }
        else
        {
            int zui=0;
            for(int i=1;i<=cnt;i++)
            {
                int mx=0;
                for(int j=1;j<=n;j++)
                {
                    if(fa[j]!=i) continue;
                    for(int k=1;k<=n;k++)
                    {
                        if(fa[k]!=i) continue;
                        mx=mmax(abs(dis[j][k]),mx);
                    }
                }
                zui+=mx;
                ++zui;
            }
            printf("%d",zui);
        }
        return 0;
    }
    void bian(int x,int y,int z)
    {
        e++;
        l[e].u=x;
        l[e].v=y;
        l[e].d=z;
        l[e].next=lian[x];
        lian[x]=e;
    }
    void tarjan(int x)
    {
        ++num;
        dfn[x]=num;
        low[x]=num;
        pd[x]=1;
        st[++head]=x;
        for(int i=lian[x];i;i=l[i].next)
        {
            int v=l[i].v;
            if(dfn[v]==0)
            {
                tarjan(v);
                low[x]=mmin(low[x],low[v]);
            }
            else
                if(pd[v]==1)
                    low[x]=mmin(dfn[v],low[x]);
        }
        if(dfn[x]==low[x])
        {
            cnt++;
            while(1)
            {
                int tmp=st[head];head--;        
                fa[tmp]=cnt;
                pd[tmp]=0;
                if(tmp==x) break;
            }
        }
    }


  • 相关阅读:
    angular 路由请求js文件
    WeX5的简单介绍及UI的简单讲解
    JAVA 反射
    JAVA 线程
    JAVA 远程通讯机制
    用Java实现几种常见的排序算法
    自动完成
    Springmvc和poi3.9导出excel并弹出下载框
    Windows Server 搭建企业无线认证(NPS搭建)
    Windows Server 搭建企业无线认证(Radius认证方案)
  • 原文地址:https://www.cnblogs.com/hzoi-wangxh/p/7738628.html
Copyright © 2011-2022 走看看