Hopcroft-Karp算法

Hopcroft-Karp算法

该算法由John.E.Hopcroft和Richard M.Karp于1973提出,故称Hopcroft-Karp算法。

原理

为了降低时间复杂度,可以在增广匹配集合M时,每次寻找多条增广路径。这样就可以进一步降低时间复杂度,可以证明,算法的时间复杂度可以到达O(n^0.5*m),虽然优化不了多少,但在实际应用时,效果还是很明显的。

基本算法

该算法主要是对匈牙利算法的优化,在寻找增广路径的时候同时寻找多条不相交的增广路径,形成极大增广路径集,然后对极大增广路径集进行增广。在寻找增广路径集的每个阶段,找到的增广路径集都具有相同的长度,且随着算法的进行,增广路径的长度不断的扩大。可以证明,最多增广n^0.5次就可以得到最大匹配。

 

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#define Inf 0x3f3f3f3f //初始距离 
using namespace std;
const int N =3005;//最大点数 
vector<int>G[N]; //边关系 
int cx[N];//cx[i]表示左集合i顶点所匹配的右集合的顶点序号
int cy[N];//cy[i]表示右集合i顶点所匹配的左集合的顶点序号    
int dx[N],dy[N];
int nx,ny;//nx左集合顶点数,ny右集合顶点数 
int dis,vis[N];
//寻找增广路径集 
int Searchpath(){
	queue<int>p;
	dis=Inf;
	memset(dx,-1,sizeof(dx));
	memset(dy,-1,sizeof(dy));
	for(int i=1;i<=nx;i++){
		 //cx[i]表示左集合i顶点所匹配的右集合的顶点序号 
		if(cx[i]==-1){
			//将未匹配的节点 入队 并初始化次节点距离为0 
			p.push(i);
			dx[i]=0;
		}
	}
	 //广度搜索增广路径 
	while(!p.empty()){
		int u=p.front();
		p.pop();
		if(dx[u]>dis) break;
		//取右集合顶点 
		for(int i=0;i<G[u].size();i++){
			int v=G[u][i];
			//右侧节点的增广路径的距离
			if(dy[v]==-1){
				dy[v]=dx[u]+1;//v对应的距离 为u对应距离加1
				if(cy[v]==-1) dis=dy[v];
				else{
					dx[cy[v]]=dy[v]+1;
					p.push(cy[v]);
				}
			}
		}
	}
	return dis!=Inf;
}
//寻找路径 深度搜索
int Findpath(int u){
	for(int i=0;i<G[u].size();i++){
		//如果该点没有被遍历过 并且距离为上一节点+1 
		int v=G[u][i];
		if(!vis[v]&&dy[v]==dx[u]+1){
			vis[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 MaxMatch(){
	memset(cx,-1,sizeof(cx));
	memset(cy,-1,sizeof(cy));
	int ans=0;
	while(Searchpath()){
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=nx;i++){
			if(cx[i]==-1){
				ans+=Findpath(i);
			}
		}
	}
	return ans;
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	nx=ny=n;
	for(int i=0;i<m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		G[a].push_back(b);
		G[b].push_back(a);
	}
	printf("%d\n",MaxMatch()/2);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值