【学习笔记】匈牙利算法

【图论】二分图最大匹配——匈牙利算法

二分图

相当好理解

这是百度百科的定义

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

听不懂吧

其实就是一个图能正好分成两部分,每个部分内的点互相没有边就是二分图

二分图的判定

用两种颜色,让相连的点的颜色不同就好啦

如果要染色的点已经有颜色了,并且和当前这个点的颜色相同,那么说明发生了矛盾,也就是这张图不是二分图

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;

const int maxn=1e5+5;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')
		{
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

bool check;

int n,m;

int tot;

int col[maxn];

int head[maxn];

struct edge
{
	int to;
	int next;
}e[maxn*2];

void add(int x,int y)
{
	tot++;
	e[tot].to=y;
	e[tot].next=head[x];
	head[x]=tot;
}

bool dfs(int x,int c)
{
	col[x]=c;
	
	for(int i=head[x];i;i=e[i].next)
	{
		int to=e[i].to;
		
		if(!col[to])
		{
			if(dfs(to,-c))
			{
				return true;
			}
		}
		else if(col[to]==c)
		{
			return true;
		}
	}
	
	return false;
}

int main()
{
	n=read();
	m=read();
	
	for(int i=1;i<=m;i++)
	{
		int u=read();
		int v=read();
		add(u,v);
		add(v,u);
	}
	
	for(int i=1;i<=n;i++)
	{
		if(!col[i])
		{
			check=dfs(i,1);
		}
		if(check==true)
		{
			break;
		}
	}
	
	if(check)
	{
		cout<<"No";
	}
	else
	{
		cout<<"Yes";
	}
	
	return 0;
}

二分图最大匹配

匈牙利算法

很简单啦

先枚举左部点u,然后和右边的v匹配,如果当前的匹配的这个右部点v已经和另一个左部点w匹配了,就让原来匹配的左部点w换一个(他会同意的,除非他没有其他选择了),如果w没得换那u只能单着了(可怜)

代码很短,就是个dfs

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>

using namespace std;

const int maxn=5e4+5;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')
		{
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

int tot,ans;

int head[maxn];

int n,m,num_e;

int match[maxn];

bool vis[maxn];

struct edge
{
	int to;
	int next;
}e[maxn];

void add(int x,int y)
{
	tot++;
	e[tot].to=y;
	e[tot].next=head[x];
	head[x]=tot;
}

bool dfs(int x)
{
	for(int i=head[x];i;i=e[i].next)
	{
		int to=e[i].to;
		
		if(!vis[to])
		{
			vis[to]=true;
			
			if(!match[to] || dfs(match[to]))
			{
				match[to]=x;
				return true;
			}
		}
	}
	
	return false;
}

int main()
{
	n=read();
	m=read();
	num_e=read();
	
	for(int i=1;i<=num_e;i++)
	{
		int u=read();
		int v=read();
		add(u,v);
	}
	
	for(int i=1;i<=n;i++)
	{
		memset(vis,false,sizeof(vis));
		if(dfs(i))
		{
			ans++;
		}
	}

	cout<<ans;
	
	return 0;
}

生まれつき何も持っていないからこそ、私たちはすべてを持つことができます

posted @ 2022-09-21 08:12  NinT_W  阅读(22)  评论(0编辑  收藏  举报