首先  摆出概念

二分图

设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

如图  就是顶点能分成两部分 且两部分内的顶点互相不连的图  就是二分图

匹配

在图论中,一个「匹配」(matching)是一个边的集合,其中任意两条边都没有公共顶点

最大匹配

一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。

比如 图一的两条红线就是一个匹配  图二也是一个匹配 并且 图二是最大匹配

            图一                       图二

匈牙利算法

匈牙利算法用来求二分图的最大匹配数

原理解析  建议搭配食用:https://blog.csdn.net/holly_Z_P_F/article/details/89043041

简述以下这个算法的思路

两个顶点集合 A {a1,a2,a3,a4....}     B{b1,b2,b3,b4.......}

我们给顶点B集中的点做匹配  枚举B中顶点 每个都作如下操作

搜索 和 b1 有连线且没搜索过的点   假设是a1

        如果 a1还没做匹配(link[a1]==0) 那就 link[a1]=b1  代表和b1连上了

        如果a1已经和b2做了匹配了  那就b2能不能换个匹配的 能换就换 让a1和b1连 不能换 那b1再试试别的

借助题目看下

模板题51nod2006

代码+注释

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
int x,y,n,m,cnt;
int e[110][110];
int v[10000];
int link[10000];
bool find(int x){
    for(int i=1;i<=n-m;i++){//遍历B集合
        if(e[x][i]&&!v[i]){//有连线且未标记
            v[i]=1;/标记
            //B中的这个点还没匹配或者已经匹配了但是所匹配的点还能换
            if(link[i]==0||find(link[i])){
                link[i]=x;return true;//匹配上
            }
        }
    }
    return false;
}
int main(){
    scanf("%d%d",&m,&n);
    while(scanf("%d%d",&x,&y)&&x!=-1&&y!=-1){
        e[x][y-m]=1;//代表连线
    }
    for(int i=1;i<=m;i++){//枚举A集合
        memset(v,0,sizeof(v));
        if(find(i))cnt++;
    }
    printf("%d\n",cnt);
    return 0;
}