什么是匈牙利算法
匈牙利算法是在两个集合中,各选出一个元素,若这两个元素情投意合,那么这两个元素就会脱离他们对应的集合,直到剩余集合中元素不能再组成配对为止(即在两个箱子里拿小球,如果这两个小球能消消乐,那么就拿到不能再消为止),匈牙利算法目的则是让匹配对数最多。
就像极度理性的男女分配一样,假如男1喜欢女1,男1也喜欢女2,但男2只喜欢女1,,那么在匹配的过程中,男2就找男1谈:“诶,我们都是兄弟,你看,我就只喜欢女1,喜欢其它人那不如让我狗带,你不也喜欢女2么,这不是两全其美。”(我纯爱战士表示狂怒,就和那个灵笼一样,所以这个ntr算法…【划掉】)
算法实现前的思路(一级结论)
1、匹配成功就要从集合中去除,但后面仍会拿来去匹配
2、两个匹配的元素只有一条无向边,所以从哪个集合先拿出小球开始匹配都可以
3、目的是尽可能多的匹配,所以当一个集合元素在另一个集合的元素都已经完成匹配时,要看看自己能不能ntr一下。
4、要考虑一个集合的每个元素n个,后面最坏情况要考虑每一条无向边m条,所以时间复杂度为O(nm)。
怎么用代码实现(二级结论)
1、因为只用看一个集合,所以,可以用数组来模拟单向指针(只要开一个数组match[],用这个数组存储前一个集合的下标1~n,这样就可以看成指向前一个集合的指针,来表示匹配了哪个元素)
2、可以用递归(函数套用来实现),find(x)函数功能是找到x这个元素的伴侣,而find(find(y))则是去找已经找到伴侣的能不能换一个。
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=503,M=1e5+3;
int n1,n2,m;
int match[N]; //储存前一个集合的下标
int st[N]; //在一次寻找中,一个女的只考虑一次,防止重复搜索
int e[M],ne[M],idx,h[N];
void add(int a ,int b) //链表存储
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
bool find(int x)
{
for(int i=h[x];i!=-1;i=ne[i]) //找一下自己喜欢的女孩有谁
{
int j=e[i];
if(!st[j])
{
st[j]=true;
if(match[j]==0||find(match[j]))//match[j]==0表示那个女生没有男朋友,find(~)表示可以ntr
{
match[j]=x; //赋值表示地址存放 ,指针指向前一个集合
return true;
}
}
}
return false;
}
int main()
{
int res=0;
memset(h,-1,sizeof h);
cin>>n1>>n2>>m;
while (m -- )
{
int a,b;
cin>>a>>b;
add(a,b);
}
for(int i=1;i<=n1;i++)
{
memset(st,false,sizeof st); //每一次都要初始化
if(find(i))res++; //如果匹配成功,result++
}
cout<<res<<endl;
}