二分匹配Hopcroft-Karp算法

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 110;
const int INF=0x7fffffff;
int bmap[N][N];//每次记得清空
//对于两边各50000个点,200000条边的二分图最大匹配可以在1s内出解,效果很好:)
struct HK{//用HK算法求解二分最大匹配问题(时间复杂度为sqrt(v)*e)
    int nx,ny,dis;
    int cx[N];//cx[i]表示左集合i顶点所匹配的右集合的顶点序号
    int cy[N]; //cy[i]表示右集合i顶点所匹配的左集合的顶点序号
    int dx[N];
    int dy[N];
    int Q[N];
    bool bmask[N];
    bool searchpath(){//极大最短增广路集
        int front,rear;
        front=rear=0;//初始化队列
        dis=INF;
        memset(dx, -1, sizeof(dx));
        memset(dy, -1, sizeof(dy));
        for(int i=1;i<=nx;i++){
            if(cx[i]==-1)//左边未匹配
            {
                Q[rear++]=i;//将左边节点放入队列
                dx[i]=0;//分层 所有潜在起点构成0层
            }
        }
        
        while(front<rear){
            int u=Q[front++];//u都是未匹配的
            if(dx[u]>dis)break;
            for(int v=1;v<=ny;v++){
                if(bmap[u][v]&&dy[v]==-1){//相邻未分层构成i+1层。
                    dy[v]=dx[u]+1;//v对应的距离 为u对应距离加1
                    if(cy[v]==-1)dis=dy[v];//右侧未匹配,更新最短距离
                    else{
                        dx[cy[v]]=dy[v]+1;//右侧已经匹配,根据已匹配边回溯。分层
                        Q[rear++]=cy[v];//左侧已匹配点入队。
                    }
                }
            }
        }
        return dis!=INF;
    }
    int findpath(int u){//只搜索极大最短增广路集中的边
        for(int v=1;v<=ny;v++){
            if(!bmask[v]&&bmap[u][v]&&dy[v]==dx[u]+1){//反向搜索的过程
                bmask[v]=1;
                if(cy[v]!=-1&&dy[v]==dis)continue;
                if(cy[v]==-1||findpath(cy[v])){
                    cy[v]=u;
                    cx[u]=v;
                    return 1;
                }
            }
        }
        return 0;
    }
    int Max_match(){
        int res=0;
        memset(cx,-1,sizeof(cx));
        memset(cy,-1,sizeof(cy));
        while(searchpath()){
            memset(bmask, 0, sizeof(bmask));
            for(int i=1;i<=nx;i++){
                if(cx[i]==-1){
                    res+=findpath(i);
                }
            }
        }
        return res;
    }
};
HK hk;
//调用的时候确定hk.nx,hk.ny,然后直接调用Max_match()就行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值