• BZOJ_2788_[Poi2012]Festival_差分约束+tarjan+floyed


    BZOJ_2788_[Poi2012]Festival_差分约束+tarjan+floyed

    Description


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

    Input

    第一行三个正整数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),表示第二类限制。

    Output

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

    如果无解输出NIE。

    Sample Input

    4 2 2

    1 2

    3 4

    1 4

    3 1

    Sample Output

    3


    先正常差分约束建图,将得到的图缩点。

    可以发现每个强连通分量之间互不影响,也就是可以直接加在一起。

    然后强联通分量内部求一个最长路,最长路就是合法的方案中最大的数减最小的数的最大值,这个加一就是每个强联通分量的答案。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 650
    #define M 200050
    int head[N],to[M],nxt[M],cnt,n,val[M],S[N],dfn[N],low[N],ins[N],from[M],m1,m2;
    int bl[N],scc,f[N][N],tot,top;
    inline void add(int u,int v,int w) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w; from[cnt]=u;
    }
    void dfs(int x) {
        S[++top]=x; ins[x]=1; dfn[x]=low[x]=++tot;
        int i;
        for(i=head[x];i;i=nxt[i]) {
            if(!dfn[to[i]]) {
                dfs(to[i]);
                low[x]=min(low[x],low[to[i]]);
            }else if(ins[to[i]]) {
                low[x]=min(low[x],dfn[to[i]]);
            }
        }
        if(dfn[x]==low[x]) {
            int t=S[top--];
            bl[t]=++scc; ins[t]=0;
            while(t!=x) {
                t=S[top--]; bl[t]=scc; ins[t]=0;
            }
        }
    }
    void floyd() {
        int i,j,k;
        for(k=1;k<=n;k++) {
            for(i=1;i<=n;i++) {
                for(j=1;j<=n;j++) {
                    f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
                }
            }
        }
    }
    int main() {
        scanf("%d%d%d",&n,&m1,&m2);
        int i,x,y,j,k;
        for(i=1;i<=m1;i++) {
            scanf("%d%d",&x,&y);
            add(x,y,1); add(y,x,-1);
        }
        for(i=1;i<=m2;i++) {
            scanf("%d%d",&x,&y);
            add(y,x,0); 
        }
        for(i=1;i<=n;i++) add(0,i,0);
        for(i=1;i<=n;i++) if(!dfn[i]) {
            dfs(i);
        }   
        memset(f,0x3f,sizeof(f));
        for(i=1;i<=cnt;i++) {
            f[from[i]][to[i]]=min(f[from[i]][to[i]],val[i]);
        }
        for(i=1;i<=n;i++) f[i][i]=0;
        int ans=0;
        floyd();
        for(i=1;i<=n;i++) if(f[i][i]<0) {
            puts("NIE"); return 0;
        }
        for(i=1;i<=scc;i++) {
            int re=0;
            for(j=1;j<=n;j++) {
                for(k=1;k<=n;k++) {
                    if(bl[j]==i&&bl[k]==i) {
                        //printf("%d
    ",f[j][k]);
                        re=max(re,f[j][k]);
                    }
                }
            }
            ans+=re+1;
        }
        printf("%d",ans);
    }
    
  • 相关阅读:
    取某个关键词以及之后的数据
    从SQL下载大量数据到Excel
    SQL 分页
    whereis linux文件搜索
    crontab Linux定时器工具
    Angular
    工具
    百度OAuth2.0登录
    JS事件学习 拖拽,鼠标键盘事件实例汇总
    信息栏滚动效果学习总结
  • 原文地址:https://www.cnblogs.com/suika/p/9062494.html
Copyright © 2020-2023  润新知