前言
复习acwing算法基础课的内容,本篇为讲解基础算法:匈牙利算法,关于时间复杂度:目前博主不太会计算,先鸽了,日后一定补上。
一、匈牙利算法
下图来自:ACWing算法基础课
匈牙利算法是用来寻找二分图最大匹配的算法具体实现方式下面做讲解:
我们把两个集合分为男,女两个集合,其中的每一条黑线都意味着这一对儿男女之间有感情,我们要做的,是看看能最多有多少对男女能够实现配对,下面我们一步一步看:
我们遍历每一个男生,那么一号男嘉宾和二号女嘉宾之间有一条线,证明他俩可成,我们标注一下
显然我们不能脚踏两条船,第一个男生已经心有所属,所以我们来看第二个男生,发现二号男嘉宾可以与一号女嘉宾实现配对,我们同样标记一下,代表他俩在一起了
接着,看到三号男嘉宾只喜欢二号女嘉宾,没有其他的选项了,那么我们把他们连一条线
尴尬的情况发生了,我们的二号女嘉宾居然脚踏两条船!!!,显然社会上不允许这样,那么二号女嘉宾就甩掉了一号男嘉宾
但是,一号男嘉宾也不是没有准备,一号男嘉宾还有一位“备胎”,四号女嘉宾,所以被甩了之后,就找上了四号女嘉宾
那么最后来看我们的四号男嘉宾,四号男嘉宾和三号女嘉宾之间有感情,同样上述操作
至此,所有的男女嘉宾都找到了自己的心上人,匈牙利算法结束
二、AcWing 861. 二分图的最大匹配
本题链接:AcWing 861. 二分图的最大匹配
本博客给出本题截图:
本题分析
注意本题是无向图,但是根据我们上述的对匈牙利算法实现的讲解中可以看出来,其实我们只需要当成有向图去做就好了,即当成男追女,而不是双向奔赴.
match数组代表的含义就是找对象,match[i] = j;
的意思就是女朋友i的男朋友为j,match[j] == 0
意味着没有男朋友
st数组的含义是是否被选定了,st[i] == false
意味着i这个女嘉宾没有被其他男嘉宾选定
if (match[j] == 0 || find(match[j]))
{
match[j] = x;
return true;
}
这里的意思是如果j号女嘉宾没有男嘉宾,或者j号女嘉宾现在的对象有备胎,那么就让j号女嘉宾成为x号男嘉宾的对象
for (int i = 1; i <= n1; i ++ )
{
memset(st, false, sizeof st);
if (find(i)) res ++ ;
}
每一个男嘉宾开始寻找女嘉宾的时候,都是默认女嘉宾没有对象的,因为有对象就抢
AC代码
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 510, M = 100010;
int n1, n2, m;
int h[N], e[M], ne[M], idx;
int match[N];
bool st[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] = x;
return true;
}
}
}
return false;
}
int main()
{
scanf("%d%d%d", &n1, &n2, &m);
memset(h, -1, sizeof h);
while (m -- )
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
}
int res = 0;
for (int i = 1; i <= n1; i ++ )
{
memset(st, false, sizeof st);
if (find(i)) res ++ ;
}
printf("%d\n", res);
return 0;
}
三、时间复杂度
关于匈牙利算法的时间复杂度以及证明,后续会给出详细的说明以及证明过程,目前先鸽了。