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);
}
原文地址:https://www.cnblogs.com/suika/p/9062494.html