Hopcroft-Karp算法的代码理解

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define ll long long
using namespace std;
const int N = 3050;
const int INF = 0x3f3f3f3f;

int dis;				//增广路的长度
int xlink[N],ylink[N];	//xlink[i]表示左集合顶点所匹配的右集合顶点序号,ylink[i]表示右集合i顶点匹配到的左集合顶点序号
int dx[N],dy[N];		//dx,dy表示增广路中从起点到该点的距离
int head[N],tot;
int vis[3005];

void init() {
    tot=0;
    memset(xlink,-1,sizeof(xlink));
    memset(ylink,-1,sizeof(ylink));
    memset(head,-1,sizeof(head));
}

void addedge(int s,int e) {
    edge[tot].v = e;
    edge[tot].next = head[s];
    head[s] = tot++;
}

int bfs() {
    queue<int>q;
    dis = INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=1; i<=m; i++) {
        if(xlink[i]==-1) {
            q.push(i);
            dx[i] = 0;
        }
    }
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int e=head[u]; e!=-1; e=edge[e].next) {
            int v = edge[e].v;
            if(dy[v]==-1) {
                dy[v] = dx[u]+1;//增广路长度+1
                if(ylink[v]==-1) dis = dy[v];//找到增广路,dis表示增广路的长度
                else {//点v已经与其它点相连,就将已经与v相连的点(这个点用vv表示)加入队列中,寻找是否有其它的点与vv相连
                    dx[ylink[v]] = dy[v]+1;
                    q.push(ylink[v]);
                }
            }
        }
    }
    return dis!=INF;
}

int dfs(int u) {
    for(int e=head[u]; e!=-1; e=edge[e].next) {
        int v = edge[e].v;
        if(!vis[v]&&dy[v]==dx[u]+1) {//dy[v]==dx[u] + 1表示在增广路中v是u的下一个点
            vis[v] = 1;
            if(ylink[v]!=-1&&dy[v]==dis) continue;
            //ylink[v]!=-1 表示 x 中有与 v 相连的
            //dy[v] == dis 表示 v 点是增广路中的最后一个点,
            if(ylink[v]==-1||dfs(ylink[v])) {
                xlink[u] = v;
                ylink[v] = u;
                return 1;
            }
        }
    }
    return 0;
}

int MaxMatch() {
    int ans=0;
    while(bfs()) {//bfs寻找一条增广路
        memset(vis,0,sizeof(vis));
        for(int i=1; i<=m; i++) {
            if(xlink[i]==-1) {
                ans+=dfs(i);
            }
        }
    }
    return ans;
}

int main() {
    addedge(1,3);
    addedge(1,4);
    addedge(1,6);
    addedge(2,1);
    addedge(2,3);
    addedge(2,4);
    addedge(2,6);
    addedge(3,3);
    addedge(4,6);
    addedge(4,6);
    addedge(5,2);
    addedge(5,5);
    addedge(5,6);
    int ans=MaxMatch();
    printf("%d\n\n",ans);
    return 0;
}

图片来自该博客:https://www.cnblogs.com/DWVictor/p/11348382.html
以上图为例,第一次bfs之后使用匈牙利算法形成的匹配:
在这里插入图片描述
由图可知左集合中点4未匹配,再一次bfs找一条增广路:
在这里插入图片描述
第二次使用bfs寻找增光路时dx与dy的变换情况 :
dx[4] = 0->dy[6] = 1->dx[1] = 2->dy[4] = 3(dy[3] = 3)->dx[2] = 4->dy[1] = 5;最后在右集合中找到了编号为1的未匹配点,找到了一条长度为5的增广路,再用匈牙利算法计算最大匹配.
在这里插入图片描述
上图就是最后找到的最大匹配.

代码参考于该博客
第一张图借鉴于该博客

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值