P3386 【模板】二分图最大匹配

本文介绍了如何利用二分图理论解决最大匹配问题,以洛谷题目为例,通过数组模拟链表和unordered_map数据结构实现匹配过程,展示了深度优先搜索策略的应用。
摘要由CSDN通过智能技术生成

本题链接:【模板】二分图最大匹配 - 洛谷

题目:

样例1:

输入
1 1 1
1 1

输出
1

 样例2:

输入
4 2 7
3 1
1 2
3 2
1 1
4 2
4 1
1 1

输出
2

思路:

        根据题目意思,我们由之前提及到过的二分图含义明确一下。

        二分图就像是一个人群中的男女混合舞会,所有参与者可以分成两组:男生和女生。在这个舞会上,男生只和女生跳舞,而不和其他男生跳舞;女生也只和男生跳舞,而不和其他女生跳舞。没有两个男生或两个女生会成对跳舞。只存在一对一个的关系。

        换句话说,如果一个图是二分图,就意味着可以将所有的点分成两组,使得同一组内的点之间没有直接相连的边,而不同组内的点之间有直接相连的边。这种特性在很多实际问题中都有重要的应用。

        这里二分图最大匹配 的可以理解为 : 找出尽可能多的能够一对一个结点不同染色结点的对数总量.

代码详解如下:

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#define endl '\n'
#define int long long
#define YES puts("YES")
#define NO puts("NO")
#define umap unordered_map
#define All(x) x.begin(),x.end()
#define IOS std::ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
using namespace std;
const int N = 2e6 + 10;

int n,m,k,ans;

// 数组模拟链表
vector<int>h(N,-1);
int e[N],ne[N],idx;
inline void Add(int a,int b)
{
	e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

umap<int,int>stn; // 表示 n 种类的结点是否已经匹配过
umap<int,int>stm; // 表示 m 种类的结点是否已经匹配过

inline bool Finds(int x)
{
	// 枚举当前结点所指向的对应 另一个种类的结点
	for(int i = h[x];i != -1;i = ne[i])
	{
		int j = e[i];	// 取出对应的结点
		if(!stm[j])	// 如果对应的结点没有匹配
		{
			stm[j] = true;	// 标记该节点可以匹配
			
			// 如果对应 m 结点没有匹配,我们将其匹配
			// 或者 匹配过了,那让 当前 m 结点匹配过了的,再另找是否有没匹配的
			if(!stn[j] || Finds(stn[j]))
			{
				stn[j] = x;
				return true;	// 返回匹配成功
			}
		}
	}
	return false;	// 如果找了一整圈下来匹配不成功,返回 false
}


inline void solve()
{
	cin >> n >> m >> k ;
	while(k--)
	{
		int a,b;
		cin >> a >> b;
		
		// 这里之所以不双向相连,
		// 是因为我们匹配查找的时候只需要遍历另一个种类的结点,找出对应的一个结点
		// 所以没必要双向连接
		Add(a,b);		
	}
	
	// 枚举 我们由 连接方式对应的种类结点,
	// 因为我们是 由 属于 n 种类的 指向 m 种类的对应结点
	// 所以我们遍历 n 个结点,属于 n 种类的
	for(int i = 1;i <= n;++i)
	{
		// 这里清除我们原先所有的匹配 m ,重新以当前的结点开始进行查找匹配
		stm.clear();	 
		if(Finds(i)) ++ans;	// 如果当前结点可以查找到匹配,那么成功数量 + 1
	}
	
	cout << ans << endl;
}

signed main()
{
//	freopen("a.txt", "r", stdin);
//	IOS;
	int _t = 1;
//	cin >> _t;
	while (_t--)
	{
		solve();
	}

	return 0;
}

最后提交:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值