二分图最大匹配(匈牙利算法&Dinic算法)

二分图最大匹配:

给出一个二分图,左边有若干个节点,右边有若干个节点,左边的节点想到匹配右边的节点,每个左边的节点每个都有若干个可以选择的对象,每个左边节点只能选择一个右边节点,每个右边节点也只能被选择一次。现在问你左边的节点能完成匹配的做多能有几个?

通俗一点就是,有一群人,有一堆奖品,每个人都有自己心仪的奖品,每种奖品只有一份,问你最多能有多少能拿到自己心仪的奖品(每个人只能拿一份,而且每个人可能有多重心仪的奖品)?

匈牙利算法:

匈牙利算法的做法就是,先让每个左边节点去匹配,如果存在没有被匹配到的右边节点,那就直接匹配。否则,则询问右边被匹配节点的匹配者,看它是否还有别的选择。
题目

#include

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正合适

你可能感兴趣的:(图论)