网络最大流SAP算法

来源:互联网 发布:unity3d简介 编辑:程序博客网 时间:2024/05/18 00:47
#include<cstdio>//拆点 将1~n的女生每个拆成两个分别为n+1到2*n,坏女生连的是和自己关系不好的男生#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int INF=0x7fffffff;int f[100010],n,m,p,k,cont,arr[1010][1010],dis[100010],gap[100010],first[100010];int cur[100010];//当前弧int exc[100010];//该点盈余int pre[100010];//前驱节点struct node{    int u,v,w;    int next;} x[100010];struct zp{    int a,b;} edge[100010];int finds(int a){    int b=a;    while(a!=f[a])        a=f[a];    while(b!=a)    {        int tmp;        tmp=f[b];        f[b]=a;        b=tmp;    }    return a;}int merger(int a,int b){    int fa=finds(a),fb=finds(b);    if(fa!=fb)        f[fa]=fb;}void add_edge(int a,int b,int value){    x[cont].u=a,x[cont].v=b,x[cont].w=value;    x[cont].next=first[a],first[a]=cont++;    x[cont].u=b,x[cont].v=a,x[cont].w=0;    x[cont].next=first[b],first[b]=cont++;}void build(int flow)//建图{    cont=0;    memset(first,-1,sizeof(first));    memset(arr,0,sizeof(arr));    for(int i=0; i<m; i++)    {        int a=edge[i].a,b=edge[i].b;        arr[finds(a)][b]=1;//用老大来和自己的朋友建立关系    }    for(int i=1; i<=n; i++)    {        add_edge(2*n+i,3*n+1,flow);//男生向汇点建边        add_edge(0,i,flow);//源点向女生建边        add_edge(i,i+n,k);//好女生向坏女生建边        for(int j=1; j<=n; j++)            if(arr[finds(i)][j]) add_edge(i,2*n+j,1);//如果老大和该男生是朋友则自己也和该男生是朋友            else add_edge(i+n,2*n+j,1);//否则不是朋友    }}int SAP(int s,int e,int N)//源点,汇点,总点数{    int Max_flow=0,u=s;    pre[s]=-1;    exc[s]=INF;    memset(gap,0,sizeof(gap));//标号是i的点的个数    memset(dis,0,sizeof(dis));//距离标号    gap[0]=N;    for(int i=0; i<=N; i++) //初始化当前弧        cur[i]=first[i];    while(dis[s]<N)    {        int flag=1;        if(u==e)//找到汇点        {            Max_flow+=exc[e];//更新最大流            for(int i=pre[e]; i!=-1; i=pre[i]) //更新当前允许路            {                int id=cur[i];                x[id].w-=exc[e];                x[id^1].w+=exc[e];                exc[i]-=exc[e];                if(x[id].w==0) u=i;//退回到容量为0的弧尾            }        }        for(int i=cur[u]; i!=-1; i=x[i].next) //从当前弧开始寻找允许弧        {            int v=x[i].v;            if(x[i].w>0&&dis[u]==dis[v]+1)//找到允许弧            {                flag=0;//找到允许弧                cur[u]=i;//更新当前弧                pre[v]=u;//记录前驱                exc[v]=min(exc[u],x[i].w);//计算最大增广                u=v;                break;            }        }        if(flag)//没有找到允许弧        {            if(--gap[dis[u]]==0) break;//出现断层结束            int minn=N;            cur[u]=first[u];            for(int i=first[u]; i!=-1; i=x[i].next) //找离当前点可到达的最小层次            {                int v=x[i].v;                if(x[i].w>0&&dis[v]<minn)                {                    minn=dis[v];                    cur[u]=i;//修改当前弧标记                }            }            dis[u]=minn+1;//更新该点层次            gap[dis[u]]++;//层次点数++            if(u!=s) u=pre[u];//回溯继续寻找允许弧        }    }    return Max_flow;}int main(){    int ncase;    scanf("%d",&ncase);    while(ncase--)    {        scanf("%d%d%d%d",&n,&m,&k,&p);        for(int i=0; i<=n; i++)            f[i]=i;        for(int i=0; i<m; i++)            scanf("%d%d",&edge[i].a,&edge[i].b);        for(int i=0; i<p; i++)        {            int a,b;            scanf("%d%d",&a,&b);            merger(a,b);        }        for(int i=1; i<=n; i++)            f[i]=finds(i);        int L=0,R=n,ans=0;        while(L<=R)//二分求解        {            int mid=(L+R)>>1;            build(mid);            if(SAP(0,3*n+1,3*n+2)==mid*n)            {                L=mid+1;                ans=mid;            }            else                R=mid-1;        }        printf("%d\n",ans);    }}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 母乳脂肪含量高怎么办 混合喂养宝宝拉肚子怎么办 混合喂养不吃奶粉怎么办 混合喂养宝宝便秘怎么办 混合喂养不吃奶瓶怎么办 混合喂养厌奶粉怎么办 气血虚奶水少怎么办 产后奶水不足怎么办啊 婴儿吐奶瓣和水怎么办 一岁半宝宝频繁喝夜奶怎么办 婴儿腹泻不吃奶怎么办 八个月宝宝脱水怎么办 宝宝呕吐脱水了怎么办 宝宝腹泻没精神怎么办 小孩拉稀没精神怎么办 宝宝拉稀脱水了怎么办 宝宝发烧还拉肚子怎么办 宝宝发烧后腹泻怎么办 吃海鲜拉肚子了怎么办 孕妇吃海鲜腹泻怎么办 稀饭煮焦了怎么办 8月宝宝拉肚子怎么办 满月宝宝38度怎么办 未满月婴儿拉稀怎么办 未满月宝宝拉稀怎么办 满月的宝宝拉稀怎么办 十个月小孩拉肚子怎么办 十个月宝宝脱水怎么办 宝宝拉肚子老不好怎么办 孩子拉稀老不好怎么办 宝宝拉肚子发呕怎么办 刚出生婴儿拉肚子怎么办 宝宝一岁拉肚子怎么办 刚出生宝宝拉肚子怎么办 宝宝出生五天拉肚子怎么办 生完宝宝拉肚子怎么办? 宝宝6天拉肚子怎么办 十天婴儿拉肚子怎么办 十天小孩拉肚子怎么办 肠炎宝宝一直吐怎么办 初生婴儿老打嗝怎么办