BZOJ 2788 Poi2012 Festival 差分约束+Tarjan+Floyd

来源:互联网 发布:数据仓库与数据集市 编辑:程序博客网 时间:2024/05/16 14:55

题目大意:给定n个正整数变量和m1+m2个限制条件,每个形如xi+1=yixi<=yi,求这些变量最多能有多少个不同的取值

首先我们可以根据差分约束建图,Floyd跑最短路,判断是否无解
然后Tarjan缩点,显然不同强连通分量之间互不影响
一个强连通分量内的最多取值个数等于强连通分量两两之间最短路的最大值+1

证明:
由于边权只有{0,1,1}三种,因此取值数=最大值-最小值+1
不妨设最短路的最大值为ans,那么对于这个差分约束系统的任意一组解,我选择最小的数x和最大的数y,由于这个图强连通,因此xy必然存在至少一条路径
不妨设x>y的最短路径长度为z,那么取值数1=yxzans
显然我们可以构造出一组解使得取值数1=ans,故ans就是最大的取值数

#include <vector>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 660using namespace std;int n,m1,m2,ans;struct abcd{    int to,next;}table[200200];int head[M],tot;int f[M][M];int dpt[M],low[M],T;void Add(int x,int y){    table[++tot].to=y;    table[tot].next=head[x];    head[x]=tot;}void Calculate(vector<int> &stack){    int i,j,re=0;    for(i=0;i<(signed)stack.size();i++)        for(j=0;j<(signed)stack.size();j++)            re=max(re,f[stack[i]][stack[j]]);    ans+=re+1;}void Tarjan(int x){    static int stack[M],top;    static bool v[M];    int i;    dpt[x]=low[x]=++T;    stack[++top]=x;    for(i=head[x];i;i=table[i].next)    {        if(v[table[i].to])            continue;        if(dpt[table[i].to])            low[x]=min(low[x],dpt[table[i].to]);        else            Tarjan(table[i].to),low[x]=min(low[x],low[table[i].to]);    }    if(dpt[x]==low[x])    {        int t;        vector<int> *s=new vector<int>;        do{            t=stack[top--];            v[t]=true;            s->push_back(t);        }while(t!=x);        Calculate(*s);    }}int main(){    int i,j,k,x,y;    cin>>n>>m1>>m2;    memset(f,0x3f,sizeof f);    for(i=1;i<=m1;i++)    {        scanf("%d%d",&x,&y);        Add(x,y);Add(y,x);        f[x][y]=min(f[x][y],1);        f[y][x]=min(f[y][x],-1);    }    for(i=1;i<=m2;i++)    {        scanf("%d%d",&x,&y);        Add(y,x);        f[y][x]=min(f[y][x],0);    }    for(i=1;i<=n;i++)        f[i][i]=0;    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]);    for(i=1;i<=n;i++)        if(f[i][i]<0)            return puts("NIE"),0;    for(i=1;i<=n;i++)        if(!dpt[i])            Tarjan(i);    cout<<ans<<endl;    return 0;}
2 0
原创粉丝点击