增广路定理:
我们用未覆盖点来表示不与任何匹配边邻接的点,其他点为匹配点,即恰好和一条匹配边邻接的点。从未覆盖点出发,依次经过非匹配边,匹配边,非匹配边,匹配边…所得的路称为交替路。如果交替路的终点是一个未覆盖点,则称这条交替路为一条增广路,非匹配边比匹配边多一条。

增广路的作用是改进匹配,假设我们已经找到一个匹配,如何判断他 是否是最大匹配?看增广路,如果有一条增广路,呢么把此路上的匹配边和非匹配边互换,得到的匹配边比刚才多一条。反之,若找不到增广路,则当前为最大匹配

一个匹配是最大匹配的充要条件是不存在增广路,这个充要条件适用于任意图。

增广路算法:
根据增广路定理,最大匹配可以通过反复寻找增广路来求解,如何找到答案?根据定义首先找到一个未覆盖的点u作为起点,设这个u是X的结点。接下来需要选一个从u出发的非匹配边(u,v),达到Y结点v。如果v是未覆盖点。说明我们成功找到了一条增广路,如果v是匹配点,那我们下一不得走匹配边,因为一个匹配点恰好与一个匹配边邻接。设匹配点v邻接的匹配边的另一端点left[v],呢么可以理解从u直接走到了left[v],而这个left[v]也是一个X结点。如果始终没有找到覆盖点,最后会扩展出一颗匈牙利树。

这样,我们得到了一个算法,即每次选一个未覆盖点u进行DFS,注意,如果找不到u开头的增广路,则换一个未覆盖点进行DFS,且以后再也不从u出发找增广路。换句话说,如果以后存在一个从出发的增广路,呢么现在就找得到。
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=600+5;
bool line[maxn][maxn];
//line[x][y]=true表示x号女生喜欢y男生(边)
int boy[maxn];
//存储y号男生匹配边另一端的匹配点女生,如果是未覆盖点则为0
bool use[maxn];
//存储y号男生是否在这条交替路上被使用过,男生是否被别人喜欢
int k,n,m;
bool dfs(int x)
{

for(int j=1;j<=m;j++)
{
if(line[x][j]&&!use[j])
{
use[j]=true;
if(!boy[j]||dfs(boy[j]))
{
//满足上面的判断语句说明找到了增广路
//即终点是未覆盖点的交替路
boy[j]=x;
return true;

}
}
//该条路不是增广路
}

return false;

}

int main()
{
while(cin>>k)
{
if(!k)
break;
cin>>n>>m;
int x,y;
int ans=0;
memset(line,false,sizeof(line));
memset(boy,0,sizeof(boy));
while(k--)
{
cin>>x>>y;
line[x][y]=true;
}
for(int i=1;i<=n;i++)
{
memset(use,false,sizeof(use));
if(dfs(i))
ans++;
}
cout<<ans<<endl;
}

return 0;
}