zoukankan      html  css  js  c++  java
  • 二分图匹配

    首先给定二分图定义

    图中两个点集e1和e2

    然后又一些无向边

    u---v

    其中u属于e1,v属于e2

    匹配是指e1中一点u与e2中一点v相连则可以构成一个匹配

    最大匹配是每个点仅属于一个匹配的情况下的最多匹配数

    匹配边指的是已经用于匹配的边

    增广路

    经过一条非匹配边一条匹配边一条非匹配边一条匹配边.........一条非匹配边

    然后把边的身份反转,就可以使总匹配数+1

    例如图中假设一开始2-5,3-6 为非匹配边

    3-5为匹配边

    它们就可以构成一个增广路

     只要对于属于左边点集的每个点都做一次增广路,就能得到最大匹配

    解释代码中的具体执行1...n属于点集1,n+1....n+m属于点集2

    建边是建单向边,从点集1的点到点集2的点

    pp[i]表示已经与点集二的点的已有匹配编号,如果尚无匹配则为0

    vis[i]表示对点集1的点有没有加入这次的增广中

    dfs返回值表示这次增广是否成功

    之后对i=1...n每个点增广

    先将vis清0

    然后进入dfs,增广如果成功也要将pp[i]进行更改

    洛谷3386

    #include<cstdio>
    #include<cstring>
    const int N=2005;
    struct E{
        int v,n;
    }e[N*N];
    int s,fir[N],pp[N],vis[N];
    void add(int u,int v){
        e[++s].v=v;
        e[s].n=fir[u];
        fir[u]=s;
    }
    bool dfs(int u){
        for(int i=fir[u];i;i=e[i].n)
            if(!vis[e[i].v]){
                vis[e[i].v]=1;
                if(!pp[e[i].v]||dfs(pp[e[i].v])) return (pp[e[i].v]=u);
            }
        return 0;
    }
    int main(){
        int n,m,mm,u,v,ans=0;
        scanf("%d%d%d",&n,&m,&mm);
        while(mm--){
            scanf("%d%d",&u,&v);
            if(u<=n&&v<=m) add(u,v+n);
        }
        for(int i=1;i<=n;++i){
            memset(vis,0,sizeof(vis));
            if(dfs(i)) ++ans;
        }
        printf("%d",ans);
        return 0;
    } 
  • 相关阅读:
    51nod1459 迷宫游戏
    51nod2006 飞行员配对(二分图最大匹配)
    51nod2006 飞行员配对(二分图最大匹配)
    GIT学习之路第四天 远程仓库
    GIT学习之路第四天 远程仓库
    搞懂树状数组
    搞懂树状数组
    线段树基础详解
    线段树基础详解
    折半枚举(双向搜索)poj27854 Values whose Sum is 0
  • 原文地址:https://www.cnblogs.com/bzmd/p/10685880.html
Copyright © 2011-2022 走看看