二分图最大匹配:
给出一个二分图,左边有若干个节点,右边有若干个节点,左边的节点想到匹配右边的节点,每个左边的节点每个都有若干个可以选择的对象,每个左边节点只能选择一个右边节点,每个右边节点也只能被选择一次。现在问你左边的节点能完成匹配的做多能有几个?
通俗一点就是,有一群人,有一堆奖品,每个人都有自己心仪的奖品,每种奖品只有一份,问你最多能有多少能拿到自己心仪的奖品(每个人只能拿一份,而且每个人可能有多重心仪的奖品)?
匈牙利算法:
匈牙利算法的做法就是,先让每个左边节点去匹配,如果存在没有被匹配到的右边节点,那就直接匹配。否则,则询问右边被匹配节点的匹配者,看它是否还有别的选择。
题目
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n1,n2,u,v,m,mat[maxn],st[maxn];//mat数组表示第i个节点是否被匹配,如果是0则是没被匹配
int h[maxn],e[maxn],nex[maxn],cnt = 1;
void add(int a, int b){
e[cnt] = b;
nex[cnt] = h[a];
h[a] = cnt++;
}
int findE(int x){
for(int i = h[x]; i != 0; i = nex[i]){
int endd = e[i];
if(!st[endd]){
st[endd] = 1;
if(mat[endd] == 0 || findE(mat[endd])){
//没被匹配,或者匹配的人还有别的选择,则当前节点可以匹配此节点
mat[endd] = x;
return 1;
}
}
}
return 0;
}
int main(){
cin >> n1 >> n2 >> m;
int a,b,ans = 0;
while(m--){
cin >> a >> b;
add(a,b);
}
for(int i = 1; i <= n1; i++){
memset(st,0,sizeof st);
if(findE(i))ans++;//匹配到了匹配数目就加一
}
cout << ans << endl;
}
Dinic算法
Dinic属于网络流算法,也可以用于二分图匹配。可以把右边的节点连向汇点,左边的节点连向源点,然后左右有关系的再相连,于是图就搭建好了每个边的容量都是1。
可以发现右边节点连的是汇点,也就是想要到达汇点就需要经过右边的点,而要到达右边的点有需要经过左边的点,所以就可以达到匹配的效果。
座位安排
一道比较裸的题目,用来写Dinic正合适