Hopcroft-Karp算法

本文介绍使用Hopcroft-Karp算法求解二分图最大匹配问题的方法。通过BFS进行距离标号,并利用匈牙利算法进行匹配增广,提高了匹配效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

任务:给定一个二分图,用Hopcroft-Karp算法求这个二分图的最大匹配数。
说明:
dx[/]dy[/]dx[/],dy[/]分别表示二分图左右部顶点的距离标号;
mx[/]my[/]mx[/],my[/]分别表示二分图左右部顶点的匹配节点;
Hopcroft相比普通的匈牙利算法来说,由于每次是增广一系列路径,所以更快。我们每次从所有未匹配的左部节点开始BFSBFS,进行距离标号。对于每一个队列中的左部节点XX,考虑与他相邻的所有右部节点Y:如果YY是一个未匹配的右部节点,则说明至少还存在一条增广路,用一个bool变量flagflag记录,以便之后增广;否则,将YY的匹配节点加入到队列中,顺便求出距离标号。当BFS结束时,若不存在增广路(即flagflagfalsefalse),那么算法结束;否则对于每一个没有匹配的左部节点XX执行匈牙利算法的find(X)操作,在这里,find(X)find(X)过程中,只考虑这样的边uv(u,v):满足dx[u]+1=dy[v]dx[u]+1=dy[v]

模板:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
using namespace std;
#define ll long long

const int maxn = 50000;


int n1, n2;
vector<int>g[maxn + 10];  //实现邻接表;g[i]表示与左边点i相连的右边的点;
int mx[maxn + 10], my[maxn + 10];
queue<int> que;
int dx[maxn + 10], dy[maxn + 10];
bool vis[maxn + 10];

bool find(int u)
{
        for(int i = 0; i < g[u].size(); i++)
        {
            if(!vis[g[u][i]] && dy[g[u][i]] == dx[u] + 1)
            {
                vis[g[u][i]] = true;
                if(!my[g[u][i]] || find(my[g[u][i]])) {
                    mx[u] = g[u][i];
                    my[g[u][i]] = u;
                    return true;
                }
            }
        }
    return false;
}

int matching(){
    memset(mx, 0, sizeof(mx));
    memset(my, 0, sizeof(my));
    int ans = 0;
    while(true)
    {
        bool falg = false;
        while(!que.empty()) que.pop();
        memset(dx, 0, sizeof(dx));
        memset(dy, 0, sizeof(dy));
        for(int i = 1; i <= n1; i++)
            if(!mx[i]) que.push(i);
        while(!que.empty())
        {
            int u = que.front();
            que.pop();
            for(int i = 0; i < g[u].size(); i++)
            {
                if(!dy[g[u][i]]){
                    dy[g[u][i]] = dx[u] + 1;
                    if(my[g[u][i]]) {
                        dx[my[g[u][i]]] = dy[g[u][i]] + 1;
                        que.push(my[g[u][i]]);
                    }
                    else {
                        flag = true;
                    }
                }
            }
        }
        if(!flag) break;
        memset(vis, 0,sizeof(vis));
        for(int i = 1; i <= n1; i++)
            if(!mx[i] && find(i)) ans++;
    }
    return ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值