IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【图论——第十讲】匈牙利算法实现二分图的最大匹配 -> 正文阅读

[数据结构与算法]【图论——第十讲】匈牙利算法实现二分图的最大匹配

?(?˙o˙?)? 大家好, 欢迎大家光临我的博客:面向阿尼亚学习
算法学习笔记系列持续更新中~

阿



一、前言

二分图定义:

二分图又称作二部图,是图论中的一种特殊模型。设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

简而言之,就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。

二分图的匹配:

给定一个二分图 G,在 G 的一个子图 M 中,M 的边集 {E} 中的任意两条边都不依附于同一个顶点,则称 M 是一个匹配。

二分图的最大匹配:

所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。

补充概念

完美匹配:

如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。

推荐大家几个学图论的工具

数据结构和算法可视化工具
图形编译器


二、匈牙利算法的实现

推荐图的存储与遍历

存图,采用邻接表来存稀疏图

//邻接表写法,存稀疏图
int h[N],ne[N],e[N],idx;

void add(int a , int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void init()
{
    memset(h,-1,sizeof h);
}
//存边只存一边就行了,虽然是无向图。
for(int i = 0 ; i < n ; i ++)
{
    int a,b;
    cin>>a>>b;
    add(a,b);
}

算法模板

//match[j]=a,表示点j现在与a点匹配
int match[N];
//st[]数组我称为临时预定数组,st[j]=a表示一轮模拟匹配中,点j与点a匹配了。
int st[N];

//这个函数的作用是用来判断,如果加入x来参与匹配,会不会使匹配数增多
int find(int x)
{
    //遍历点x连接的点
    for(int i = h[x] ; i != -1 ;i = ne[i])
    {
        int j = e[i];
        if(!st[j])//如果在这一轮模拟匹配中,这个点尚未被预定
        {
            st[j] = true;//那x就预定这个点
            //如果点j没有匹配点,或者她原来的点能够预定其它点。配对成功,更新match
            if(!match[j]||find(match[j]))
            {
                match[j] = x;
                return true;
            }

        }
    }
    return false;
}

//记录最大匹配
int res = 0;
for(int i = 1; i <= n1 ;i ++)
{  
    //因为每次模拟匹配的预定情况都是不一样的所以每轮模拟都要初始化
    memset(st,false,sizeof st);
    if(find(i)) 
        res++;
}  

【模板】二分图最大匹配

【模板】二分图最大匹配

题目描述

给定一个二分图,其左部点的个数为 n n n,右部点的个数为 m m m,边数为 e e e,求其最大匹配的边数。

左部点从 1 1 1 n n n 编号,右部点从 1 1 1 m m m 编号。

输入格式

输入的第一行是三个整数,分别代表 n n n m m m e e e

接下来 e e e 行,每行两个整数 u , v u, v u,v,表示存在一条连接左部点 u u u 和右部点 v v v 的边。

输出格式

输出一行一个整数,代表二分图最大匹配的边数。

样例 #1

样例输入 #1

1 1 1
1 1

样例输出 #1

1

样例 #2

样例输入 #2

4 2 7
3 1
1 2
3 2
1 1
4 2
4 1
1 1

样例输出 #2

2

提示

数据规模与约定

对于全部的测试点,保证:

  • 1 ≤ n , m ≤ 500 1 \leq n, m \leq 500 1n,m500
  • 1 ≤ e ≤ 5 × 1 0 4 1 \leq e \leq 5 \times 10^4 1e5×104
  • 1 ≤ u ≤ n 1 \leq u \leq n 1un 1 ≤ v ≤ m 1 \leq v \leq m 1vm

不保证给出的图没有重边

AC代码

#include <iostream>
#include <cstring>
using namespace std;

const int N=510,M=1e5+7;
int n1,n2,m;
int h[N],ne[M],e[M],idx;
bool st[N];
int match[N];

void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void init()
{
	memset(h,-1,sizeof h);
}

int find(int x)
{
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(!st[j])
		{
			st[j]=true;
			if(!match[j]||find(match[j]))
			{
				match[j]=x;
				return true;
			}
		}
	}
	return false;
}



int main()
{
	init();
	cin>>n1>>n2>>m;
	while(m--)
	{
		int a,b;
		cin>>a>>b;
		add(a,b);
	}
	int res=0;
	
	for(int i=1;i<=n1;i++)
	{
		memset(st,false,sizeof st);
		if(find(i))
		res++;
	}
	cout<<res<<endl;
	return 0;
}

最后

在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-21 21:45:58  更:2022-07-21 21:47:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:20:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码