算法基础课——匈牙利算法

78 阅读3分钟

最近复习acwing的算法基础课,复习到了匈牙利算法(二分图的最大匹配),反正听y总的奇妙比喻还是很开心的,QAQ,于是复习起来也很快乐!

前置知识

首先要知道二分图是个啥东西,二分图的定义是这样的:

二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

image.png QAQ这张网图很好的告诉了我们就是可以把一张图的所有点分成两部分,使得两部分在各部分内的点之间都没有边相连,但是两部分之间有边相连(每个点都有)。

题目

这个题

2023-01-30 (2).png

输入格式

2023-01-30 (5).png

输出格式

输出一个整数,表示二分图的最大匹配数。

数据范围

1n1,n25001≤n_1,n_2≤500
1un11≤u≤n_1, 1vn21≤v≤n_2, 1m1051≤m≤10^5

输入样例:

2 2 4
1 1
1 2
2 1
2 2

输出样例:

2

那么这个题目呢,就是求二分图的最大匹配,什么意思呢,就是说题目里有所以我就不废话了,通俗易懂的讲,其实就是一个(当海王)找对象的过程,,我们可以借助前面的那张网图来理解一下 image.png 假设U是一些男生的集合,V是一些女生的集合(当然也可以反过来),然后男生找对象, 从第一个人开始,如果有喜欢的女生,那么我们就把他们配成一对,然后继续往下找,如果下一个男生喜欢的女生跟上面的不重合,那么就将他们完美匹配,如果重合了,我们就看看上一个男生有没有其他喜欢的女生,如果有的话,就让上面的男生喜欢其他女生(没有被喜欢的女生),简称下家,如果这一套操作下来,这个男生还是找不到喜欢的女生,那么这个点就更新失败。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
const int N=510,M=100010;
int idx=0,e[M],ne[M],h[M],n1,n2,m,match[N],res=0;
bool st[N];
inline void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool find(int u){//这个函数就是看能否给x男生找到女朋友
    for(int i=h[u];~i;i=ne[i]){//这里面存的是他所有有好感的女生编号
        int j=e[i];
        if(!st[j]){//如果这个女生之前没有被找个过
            st[j]=true;//现在被找过了
            if(match[j]==0 || find(match[j])){//如果这个女生之前还没有男朋友或者这个女生现在的男朋友有其他的选择(下家)。
                match[j]=u;//那么我们就把x给这个女生做男朋友
                return true;//那么这个男生就找到女朋友了。
            }
        }
    }
    return false;//如果经过不懈努力,还是找不到女朋友,那就只好单身了。
}

int main(){
    memset(match,0,sizeof match);
    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,0,sizeof st);//每次操作前先要让所有的女孩都没被找过
        if(find(i)) res++;//如果这个男生能找到女朋友,就res++
    }
    printf("%d\n",res);/。看完美配对的对数。
    return 0;
    
}

希望能过审QAQ!