hdu3081 最大流

来源:互联网 发布:当兵对网络教育学籍 编辑:程序博客网 时间:2024/06/16 23:44
思路见来自某大牛:
题目大意:
n个男孩n个女孩,女孩选男孩,每个女孩都要选到不同的人
k对女孩有相同选择标准,
女孩每轮都选择没选过的男孩,
问总共能选几轮。
题解:
女孩1..n,男孩n+1..2*n编号
由女孩到男孩建容量为1的边
起点st=2*n+1,到1..n建边;
n+1..2*n到终点ed=2*n+2建边
二分搜索最大容量即为答案;
#include <iostream>#include <cstring>#include <cstdio>#define MAXN 210#define MAXM 50000using namespace std;struct node{    int u,v,w;};struct node2{    int x,y;};node2 ee[MAXM];int first[210],p[MAXN];node e[MAXM];int next[MAXM],cc,n,m,f;int gap[210],d[210],curedges[210],pre[210];int map[105][105];inline void add_edge(int u,int v,int w){    e[cc].u=u;    e[cc].v=v;    e[cc].w=w;    next[cc]=first[u];    first[u]=cc;    cc++;    e[cc].u=v;    e[cc].v=u;    e[cc].w=0;    next[cc]=first[v];    first[v]=cc;    cc++;}void make_set(int n){    int i;    for(i=0;i<=n;i++)        p[i]=i;}int find_set(int i){    int j=i;    while(j!=p[j])        j=p[j];    return p[i]=j;}int Union(int x,int y){    x=find_set(x);    y=find_set(y);    if(x==y)        return 0;    else    {        p[x]=y;        return 1;    }}void build(int t,int mid){    cc=0;    int i,j;    memset(map,0,sizeof(map));    memset(first,-1,sizeof(first));    memset(next,-1,sizeof(next));    for(i=1;i<=n;i++)    {        add_edge(0,i,mid);        add_edge(n+i,t,mid);    }    for(i=0;i<m;i++)    {        int u=ee[i].x;        int v=ee[i].y;        for(j=1;j<=n;j++)        {            if(find_set(u)==find_set(j))                if(!map[j][v])                {                    map[j][v]=1;                    add_edge(j,n+v,1);                }        }    }}int sap(int s,int t){    int cur_flow,flow_ans=0,u,tmp,neck,i;    memset(d,0,sizeof(d));    memset(gap,0,sizeof(gap));    memset(pre,-1,sizeof(sizeof(pre)));    for(i=0;i<=t;i++)        curedges[i]=first[i];    gap[0]=t+1;    u=s;    while(d[s]<t+1)    {        if(u==t)        {            cur_flow=99999999;            for(i=s;i!=t;i=e[curedges[i]].v)            {                if(cur_flow>e[curedges[i]].w)                {                    neck=i;                    cur_flow=e[curedges[i]].w;                }            }            for(i=s;i!=t;i=e[curedges[i]].v)            {                tmp=curedges[i];                e[tmp].w-=cur_flow;                e[tmp^1].w+=cur_flow;            }            flow_ans+=cur_flow;            u=neck;        }        for(i=curedges[u];i!=-1;i=next[i])            if(e[i].w&&d[u]==d[e[i].v]+1)                break;        if(i!=-1)        {            curedges[u]=i;            pre[e[i].v]=u;            u=e[i].v;        }        else        {            if(0==--gap[d[u]])                break;            curedges[u]=first[u];            for(tmp=t+1,i=first[u];i!=-1;i=next[i])                if(e[i].w)                    tmp=min(tmp,d[e[i].v]);            d[u]=tmp+1;            ++gap[d[u]];            if(u!=s)                u=pre[u];        }    }    return flow_ans;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        memset(ee,0,sizeof(ee));        memset(e,0,sizeof(e));        scanf("%d%d%d",&n,&m,&f);        int i,s=0,t=n*2+1;        for(i=0;i<m;i++)            scanf("%d%d",&ee[i].x,&ee[i].y);        make_set(t);        for(i=0;i<f;i++)        {            int u,v;            scanf("%d%d",&u,&v);            Union(u,v);        }        int l=0,r=n,ans=0;        while(l<=r)        {            int mid=(l+r)>>1;            build(t,mid);            int res=sap(s,t);            if(res>=mid*n)            {                ans=mid;                l=mid+1;            }            else                r=mid-1;        }        printf("%d\n",ans);    }    return 0;}

刚开始一直WA后来发现原来是要每运行一次SAP就要建一次图~~因为运行后会改变图的W~~~