二分图匹配的定义跟匈牙利算法的解释在网上找就行,都解释的很详细,我这里主要对算法模板的疑难点进行解答,在每一步很难理解的地方我在代码后面都详细解释了,方便大家理解。具体看代码跟代码后面的注释,感觉瞎口胡没有实际代码支撑要写出来还是很难的。(还是不理解就自己带个数据进去跑一遍,跑到一半就会理解了!)
代码:
#include<bits/stdc++.h>
#define K 100005
#define N 505
#define M 505
using namespace std;
int k,n,m,x,y,ans=0;
int gril[N];//第i个女生的归属男生
bool line[N][M],used[N];//女生i与男生j有暧昧关系,第i个女生是否已经被使用过(即已经被配对好了)
bool find(int x)
{
for(int i=1;i<=n;i++)
{
if(!used[i]&&line[i][x])
{
used[i]=1;
if(gril[i]==0||find(gril[i]))
{
gril[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
memset(line,0,sizeof(line));
memset(gril,0,sizeof(gril));
scanf("%d%d%d",&k,&n,&m);//n为女生,m为男生
for(int i=1;i<=k;i++)
{
scanf("%d%d",&x,&y);
line[x][y]=1;
}
for(int i=1;i<=m;i++)//给男生匹配
{
memset(used,0,sizeof(used));
//used每次清零的作用是在find妹子的时候我需要尽可能的满足当前第i个男生选人,然后再委屈前面的男生换女朋友
//但是我当前递归的是当前第i个男生,那么我把这个男生找到的女朋友标记,然后再递归之前的选中这个女生的男人,当find这个男人的时候,我used表示我之前选的那个女生已经被霸占了,所以就不能选了,因此used清零就是起到这个作用
//因为每次每个男生选择女生是不同的,所以used标记为1,让递归之前的男生不能够选择之前的,因此需要used清零
//越解释越乱,实在看不懂就带一组数据试试吧
if(find(i))ans++;
//这个地方很多人容易误解为,如果我当前第i个男生匹配到了女朋友,但是导致了他前面的男生找不到女朋友那么答案不是增加而是减少啊
//其实我这里满足的情况就是让前面的男生经过调整也找到女朋友,当前这个男生也找到女朋友,所以ans++
//当然还会认为一种想法就是我牺牲前面第一个或者某个男生一个人的幸福来满足其他所有人,我刚开始也是这么认为,后来想了一个晚上之后终于想通了
//如果我当前第一个人选择了那个女人,也是别人喜欢的女人,结果别人抢占了第三个人的女人,导致第三个人找不到老婆,那么我就算是把第一个人牺牲,我第二个人重新选择,第三个人再选择,那么现在就是 1无 2有 3有,之前是 1有 2有 3有,答案一样
//或者是可能会认为存在第一个人找到女朋友其他人都找不到女朋友的情况,其实这种情况也是不可能的,我这种情况只需要牺牲当前的第i个人那么前面的那些人都能找到女朋友
//因此,是不存在会有牺牲前面某个人来换取后面多人的幸福的情况,只有满足前面的人幸福的前提下才能看能不能满足当前这个人的幸福
}
printf("%d",ans);
}