二分图匹配

简介

luogu模版题传送门传送门

二分图匹配的问题是可以被网络流解决的,接下来我们来学习一下二分图匹配。

二分图匹配所使用的算法是匈牙利算法,由于匈牙利人的脑回路可能和正常人不大一样,这个算法比较的暴力,并且算法运行过程也比较有趣。

首先,我来介绍一下匈牙利算法。

匈牙利算法可以用一句话简单的概括,就是绿与被绿协调与被协调。

算法介绍

然后我来正经的说一下匈牙利算法真正的算法过程。

匈牙利算法的主要过程是,先从二分图的一侧的最小编号开始,然后向另外一侧的点从编号最小的点开始匹配。
后面的点重复以上操作,如果遇到冲突,就让这个后来的点先匹配上这个点,
与前面匹配到这个点的点被协调,重新向后寻找点进行匹配,如果无法匹配则停止匹配。
如果在向前协调时矛盾则按照上面的方式进行协调。
如果上面的协商失败,那么最大号的点继续向下匹配。

接下来是算法的演示,我相信看明白演示以后,整个算法原理和方法就很好理解了。

算法过程

我们先建出下面这个图

在这里插入图片描述

那么我们就开始匈牙利算法了, 红色的连边为匹配上的边

显然的是第一次是A和E连边,但是接下来的时候B要连边的时候需要进行协调了,所以说我们需要让A被协调,把E让给B,A就只好和F匹配了。

在这里插入图片描述

上一轮匹配完毕后图就变成呢个了下面这个样子,但是在进行下一步的时候就需要还需要一轮协商了。我们来看与C连边的最小编号的是F点了,那么我们强制C和F匹配,那么A就需要被协调了,那么A就只好和G匹配了,这轮的协商完成了。

在这里插入图片描述

那么进过上面的这个协商过后,我们的图就变成了下面这个样子,接下里我们就要 进行最复杂的协调和被协调的步骤了,和D能进行匹配的最小编号就是E了,而E和B匹配着,那么B就要被协商了。

在这里插入图片描述

那么我们来看下面这张图,是上面的话进行协商的过程图片,蓝色的是B在协商后只能连的边,那么连接的G又被A连接过,所以说A只能被协调,而A没有更大的编号连边来供他匹配了,所以说这一轮的协商失败,维持原来的情况。

在这里插入图片描述

那么下面没有可以待匹配的点了,所以匈牙利算法结束了,下面的图是匹配成功的图。

在这里插入图片描述

时间复杂度

通过上面的演示,我们可以发现最坏的情况下就是没连一条边就需要协调到底,那么时间复杂度就是 O ( n ³ ) O(n³) O(n³)了,当时最好的就是一连就匹配,就是 O ( n ) O(n) O(n)了。通常情况下我们就把他当作 O ( n ³ ) O(n³) O(n³)了。

代码

那么下面放个我的代码。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

int n,m,e;

bool f[1001][1001],vis[1001];

int py[1001],px[1001];

bool dfs(int x)
{
	for(int i=1;i<=m;i++)
	  if(f[x][i])
	    if(!vis[i])
	      {
	      	  vis[i]=1;
	      	  if(py[i]==-1||dfs(py[i]))
	      	  {
	      	      px[x]=i;
	      	      py[i]=x;
	      	      return 1;
			  }
		}
	return 0;
}

void Hungary()
{
	int ans=0;
	memset(px,-1,sizeof(px));
	memset(py,-1,sizeof(py));
	for(int i=1;i<=n;i++)
	  memset(vis,0,sizeof(vis)),ans+=dfs(i);
	cout<<ans<<endl;
	return;
}
int main()
{
	scanf("%d%d%d",&n,&m,&e);
	for(int i=1;i<=e;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(x>=1&&x<=n&&y>=1&&y<=m)
		  f[x][y]=1;
	}
	Hungary();
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值