引入
一个问题:给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数
一开始可能没有看懂题目,来解释一下几个名词
二分图,表示一张无向图有两个点集,一个点集中的点只会与另一个点集中的点相连
匹配,表示取一条边与两个没有被标记过的点,计算一次匹配并标记这两个点
思考
那怎么求解这个问题呢,我一开始想的是min(n,m)滑稽
来一种简单的反例
这幅图的最大匹配数可以看出来是2吧,反例举完了,我们来想想别的方法
数据范围是n和m在1000以内,nlogn×mlogm好像能过雾,然而并没有这种方法,那怎么办呢(:з」∠)
我们来介绍一种贪心做法,它叫匈牙利算法(╹▽╹)
匈牙利算法
不要问我为什么它叫这名字,我不知道QwQ
我们用形象的方法来讲_(:з」∠)
我们从土狼开始,给他找个CP雾
直接搜到了呆毛QwQ,建一个数组match存每个女生的CP,那么match[1]就是土狼awa
接下来到了红A,这里有一点特殊是要开一个visit数组,作用范围是每一个男生,也就是说每次搜完一个男生,就要重置一下visit数组
红A也搜到了呆毛,这里就是一波操作ntr了,因为呆毛有CP,我们找到她的CP——土狼,让土狼尝试换一个CP滑稽
土狼又搜索到了凛,就把呆毛让给红A了别打我QwQ
所以现在土狼的CP是凛,红A的CP是呆毛,我们继续往下搜
现在轮到狗哥了,他也搜到了呆毛,于是找到她的CP——红A,让红A尝试换一个,红A找到了凛,再搜凛的CP——土狼,土狼发现还有伊莉雅,就把凛让给狗哥了讲述的有点奇怪emm
那么现在土狼和伊莉雅,红A和呆毛,狗哥和凛,就是这样awa
接下来是人民教师,他搜到了C妈话说他很纯情啊,这样就搜完了,刚好有4组CP,很圆满啊
不知道大家有没有看懂整个流程,其实是这样的:
1. 搜索一个男生,找和他有好感的女生,看她有无CP,如果有,转到步骤2,如果没有,转到步骤3
2. 搜索这个女生的CP,看他能不能换一个什么鬼,搜到一个女生,如果这个女生没有CP,转步骤3,如果有,重复步骤2
3. 将搜到的女生和步骤1中的男生组成CP,标记一下
4. 最后统计答案就行啦
ac代码
讲了这么多来放一下代码吧
#include<bits/stdc++.h>
using namespace std;
struct p{int to,next;}a[2000010];
int n,m,len,head[20100],x,y,vis[20100],l=0,mach[20100],ans=0;
int dfs(int k)
{
for(int i=head[k];i!=-1;i=a[i].next)
{
if(!vis[a[i].to])
{
vis[a[i].to]=1;
if(!mach[a[i].to]||dfs(mach[a[i].to]))
{
mach[a[i].to]=k;
return 1;
}
}
}
return 0;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&len);
for(int i=1;i<=len;i++)
{
scanf("%d%d",&x,&y);
if(x>n||y>m)continue;
y+=n+1;
a[++l].to=y,a[l].next=head[x],head[x]=l;
a[++l].to=x,a[l].next=head[y],head[y]=l;
}
for(int i=1;i<=n;i++)memset(vis,0,sizeof(vis)),ans+=dfs(i);
printf("%d",ans);
return 0;
}