zoukankan      html  css  js  c++  java
  • bzoj 2788 [Poi2012]Festival 差分约束+tarjan+floyd

    题目大意

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

    分析

    差分约束,问题很新颖
    注意到图有特殊性
    限制1(1类边):双向边
    限制2(2类边):单向边
    我们考虑求强联通分量
    连接两个强联通分量的边不可能是1类边(不然强联通就合起来了)
    只可能是A<=B
    只要保证A中最大值小于B中最小值,就可以使不同权值最多
    一定是可以做到的
    那么我们只需要对每个强联通求出答案再累加起来就好了
    对于强联通中的2类边,一定是在一个环中的,一定都为一个权值(不然就分成两个连通块了)
    这一部分的最长路跑出来是0
    由于图中只有-1,0,1三种边
    每个强联通中,
    记D为任意两个点的 最长路的绝对值 的最大值
    其实D就是最大权值和最小权值的差
    所以每个连通块权值种类就是D+1

    姿势

    1.差分约束常常特判连边是否自环矛盾
    2.floyd判负环可以一开始f[i][i]=0,跑floyd的时候不判i!=j!=k,跑完后看看f[i][i]有没有变
    3.邻接矩阵建图注意重编时取max,min啥的
    4.之前我tarjan一直是写错的

    if(inst[y]) low[x]=min(low[x],dfn[y]);//注意这里是inst[i],因为有向图搜索顺序的问题,tarjan是可能跑到之前tarjan过的地方的,如果写if(dfn[y])这样会出bug
    else if(!dfn[y]){
        tarjan(y);
        low[x]=min(low[x],low[y]);
    }
    

    5.spfa时用que[],inq[]
    6.spfa时inc函数既写引用又写返回值,方便一些

    solution

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int M=607;
    const int N=100007;
    const int INF=2139062144;
     
    inline int rd(){
        int x=0;bool f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
        for(;isdigit(c);c=getchar()) x=x*10+c-48; 
        return f?x:-x;
    }
     
    int n,m1,m2;
     
    int g[M],te;
    struct edge{
        int y,d,next;
    }e[N<<1];
    struct node{
        int x,y;
        node(int xx=0,int yy=0){x=xx;y=yy;}
    }e1[N],e2[N];
     
    void addedge(int x,int d,int y){
        e[++te].y=y;e[te].d=d;e[te].next=g[x];g[x]=te;
    }
     
    int dfn[M],low[M],tdfn;
    int col[M],cnt;
    int st[M],tot;
    int vis[M];
    int f[M][M];
    int ans[M];
    int inst[M];
     
    void tarjan(int x){
        dfn[x]=low[x]=++tdfn;
        st[++tot]=x;
        inst[x]++;
        int p,y;
        for(p=g[x];p;p=e[p].next){
            y=e[p].y;
            if(inst[y]) low[x]=min(low[x],dfn[y]);//instack
            else if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
            }
        }
        if(low[x]==dfn[x]){
            ++cnt;
            while(st[tot]!=x){
                inst[st[tot]]=0;
                col[st[tot--]]=cnt;
            }
            inst[st[tot]]=0;
            col[st[tot--]]=cnt;
        }
    }
     
    void floyd(){
        int i,j,k;
        for(k=1;k<=n;k++)
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        if(f[i][k]!=-INF&&f[k][j]!=-INF){
            f[i][j]=max(f[i][j],f[i][k]+f[k][j]);
        }
    } 
     
     
     
    int main(){
         
        n=rd(),m1=rd(),m2=rd();
         
        int i,j,x,y;
         
        for(i=1;i<=m1;i++){
            x=rd(),y=rd();
            if(x==y){//²é·ÖÔ¼Êø³£¼ûÌØÅÐ 
                puts("NIE");
                return 0;
            }
            e1[i]=node(x,y);
            addedge(x,1,y);
            addedge(y,-1,x);
        }
         
        for(i=1;i<=m2;i++){
            x=rd(),y=rd();
            e2[i]=node(x,y);
            addedge(x,0,y);
        }
         
        for(i=1;i<=n;i++)
        if(!dfn[i]) 
            tarjan(i);
         
        memset(f,128,sizeof(f));
        for(i=1;i<=m1;i++){
            x=e1[i].x,y=e1[i].y;
            if(col[x]==col[y]){
                f[x][y]=max(f[x][y],1);
                f[y][x]=max(f[y][x],-1);
            }
        }
        for(i=1;i<=m2;i++){
            x=e2[i].x,y=e2[i].y;
            if(col[x]==col[y]){
                f[x][y]=max(f[x][y],0);
            }
        }
        for(i=1;i<=n;i++) f[i][i]=0;//Åиº»·Óà 
         
        floyd();
         
        for(i=1;i<=n;i++) if(f[i][i]>0){
            puts("NIE");
            return 0;
        }
         
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        if(col[i]==col[j]&&f[i][j]!=-INF) ans[col[i]]=max(ans[col[i]],abs(f[i][j]));///abs
         
        int sum=0;
        for(i=1;i<=cnt;i++) sum+=ans[i]+1;
         
        printf("%d
    ",sum);
         
        return 0;
    }
    
  • 相关阅读:
    Spring Boot 使用常见问题
    JPA 使用
    JPA 复杂查询
    Gitlab利用Webhook实现Push代码后的jenkins自动构建
    消息中间件的使用场景
    消息中间件资料整理
    js原生跨域--用script标签实现
    遍历类成员并赋值
    Spring boot 读取 application.properties 文件方法
    fastjson 进行json转实体类对象及一些常用操作
  • 原文地址:https://www.cnblogs.com/acha/p/6417237.html
Copyright © 2011-2022 走看看