hdu3277 最大流拆点+并查集

来源:互联网 发布:企业cms开源 编辑:程序博客网 时间:2024/06/16 11:13

与hdu3081非常相似 建议先做3081 然后这题只不过多了拆点 马上就过了


#include<algorithm>#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<string>#include<stack>#include<queue>#include<cmath>#include<stack>#include<list>#include<map>#include<set>typedef long long ll;using namespace std;const int MAXN=800;const int MAXM=120001200;const int INF=0x3f3f3f3f;int lun;struct Node{    int from,to,next;    int cap;}edge[MAXM];int f[255];int cap[255][255];int tol;int head[MAXN];int dep[MAXN];int gap[MAXN];int n;void init() {    tol=0;    memset(head,-1,sizeof(head));}int find1(int x){    if(f[x]==x)return x;    else return f[x]=find1(f[x]);}void addedge(int u,int v,int w){    edge[tol].from=u;    edge[tol].to=v;    edge[tol].cap=w;    edge[tol].next=head[u];    head[u]=tol++;    edge[tol].from=v;    edge[tol].to=u;    edge[tol].cap=0;    edge[tol].next=head[v];    head[v]=tol++;}void BFS(int start,int end){    memset(dep,-1,sizeof(dep));    memset(gap,0,sizeof(gap));    gap[0]=1;    int que[MAXN];    int front,rear;    front=rear=0;    dep[end]=0;    que[rear++]=end;    while(front!=rear)    {        int u=que[front++];        if(front==MAXN)front=0;        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v=edge[i].to;            if(dep[v]!=-1)continue;            que[rear++]=v;            if(rear==MAXN)rear=0;            dep[v]=dep[u]+1;            ++gap[dep[v]];        }    }}int SAP(int start,int end){    int res=0;    BFS(start,end);    int cur[MAXN];    int S[MAXN];    int top=0;    memcpy(cur,head,sizeof(head));    int u=start;    int i;    while(dep[start]<n)    {        if(u==end)        {            int temp=INF;            int inser;            for(i=0;i<top;i++)                if(temp>edge[S[i]].cap)                {                    temp=edge[S[i]].cap;                    inser=i;                }            for(i=0;i<top;i++)            {                edge[S[i]].cap-=temp;                edge[S[i]^1].cap+=temp;            }            res+=temp;            top=inser;            u=edge[S[top]].from;        }        if(u!=end&&gap[dep[u]-1]==0)            break;        for(i=cur[u];i!=-1;i=edge[i].next)            if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)                break;        if(i!=-1)        {            cur[u]=i;            S[top++]=i;            u=edge[i].to;        }        else        {            int min=n;            for(i=head[u];i!=-1;i=edge[i].next)            {                if(edge[i].cap==0)continue;                if(min>dep[edge[i].to])                {                    min=dep[edge[i].to];                    cur[u]=i;                }            }            --gap[dep[u]];            dep[u]=min+1;            ++gap[dep[u]];            if(u!=start)u=edge[S[--top]].from;        }    }    return res;}void build(int n1){    int i,j,k;    for(i=1;i<=n1;i++)    {        for(j=i+1;j<=n1;j++)        {            if(find1(i)==find1(j))            {                for(k=1;k<=n1;k++)                {                    if(cap[i][k]==1||cap[j][k]==1)                    {                        cap[i][k]=1;                        cap[j][k]=1;                    }                }            }        }    }    }int solve(int n1,int mid){    int i,j;    init();    for(i=1;i<=n1;i++)    {        addedge(0, i, mid);        addedge(i, i+n1, lun);        addedge(i+2*n1, 3*n1+1, mid);       }    for(i=1;i<=n1;i++)    {                for(j=1;j<=n1;j++)        {            if(cap[i][j]==1)            {                addedge(i, j+2*n1, 1);            }            else addedge(i+n1, j+2*n1, 1);        }    }    int flow=SAP(0,3*n1+1);    return flow;    }int main(){        int i,m,n1,f1;    int T;    scanf("%d",&T);    while(T--)    {        for(i=0;i<255;i++)f[i]=i;        memset(cap,0,sizeof cap);        scanf("%d%d%d%d",&n1,&m,&lun,&f1);        n=n1*3+2;        int x,y;        while(m--)        {            scanf("%d%d",&x,&y);            cap[x][y]=1;           // f[y+n1]=x;        }        while(f1--)        {            scanf("%d%d",&x,&y);            int fx=find1(x),fy=find1(y);            if(fx!=fy)            {                 f[fx]=fy;                            }        }        for(i=1;i<=n1;i++)f[i]=find1(i);        build(n1);        int l=0,r=n1;        int mid;        int ans=0;        while(l<=r)        {            mid=(l+r)/2;                        if(solve(n1,mid)==mid*n1)            {                l=mid+1;                ans=mid;                         }            else            {                r=mid-1;            }        }        printf("%d\n",ans);    }    return 0;}