最大匹配 人员分配

最大匹配 人员分配

Description

设有M个工人x1, x2, …, xm,和N项工作y1, y2, …, yn,规定每个工人至多做一项工作,而每项工作至多分配一名工人去做。由于种种原因,每个工人只能胜任其中的一项或几项工作。问应怎样分配才能使尽可能多的工人分配到他胜任的工作。这个问题称为人员分配问题。

Input

第一行两个整数m,n分别为工人数和工作数。
接下来一个整数s,为二分图的边数。
接下来s行,每行两个数ai,bi表示第ai个工人能胜任第bi份工作

Output

一个整数,表示最多能让多少个工人派到自己的胜任的工作上。

Sample Input

3 3
4
1 2
2 1
3 3
1 3

Sample Output

3

Hint

规模:
1<=m,n<=100
1<=s<=10000

思路:
这一道二分图——最大匹配的模板题,采用匈牙利算法;

增广路的定义(也称增广轨或交错轨):
若P是图G中一条连通两个未匹配顶点的路径,并且属M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。
求最大匹配常用匈牙利算法,它的基本思想是:对于已知的匹配M,从X中的任一选定的M非饱和点出发,用标号法寻找M增广链。如果找到M增广链,则M就可以得到增广;否则从X中另一个M非饱和点出发,继续寻找M增广链。重复这个过程直到G中不存在增广链结束,此时的匹配就是G的最大匹配。这个算法通常称为匈牙利算法,因为这里介绍的寻找增广链的标号方法是由匈牙科学者Egerváry最早提出来的。

最大匹配 人员分配_第1张图片
算法轮廓:

  1. 置M为空
  2. 找出一条增广路径P,通过取反操作获得更大的匹配M’代替M
  3. 重复(2)操作直到找不出增广路径为止

邻接矩阵

#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);

using namespace std;

const int MAX=2147483647;
const int N=1e4+10;
int n, m, s, f[N][N], a, b, ans, link[N];
bool cover[N];

bool  find(int x)
{
	for(int i=1; i<=m; i++)
	{
		if(!cover[i] && f[x][i])
		{
			cover[i]=1;
			int q=link[i];
			link[i]=x;
			if(!q || find(q)) return 1;
			link[i]=q;
		}
	}
	return 0;
}

int main()
{
	scanf("%d%d%d", &n, &m, &s);
	for(int i=1; i<=s; i++) scanf("%d%d", &a, &b), f[a][b]=1;
	for(int i=1; i<=n; i++) memset(cover, 0, sizeof(cover)), ans+=find(i);
	printf("%d", ans);
	return 0;
}

邻接表

#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);

using namespace std;

const int MAX=2147483647;
const int N=1e4+10;
int n, m, s, a, b, ans, hd[N], link[N], tot;
bool cover[N];
struct node
{
	int to, next;
} edge[N];

void add(int x, int y) {edge[++tot]=(node){y,hd[x]}, hd[x]=tot;}

bool find(int x)
{
	for(int i=hd[x]; i; i=edge[i].next)
	{
		int y=edge[i].to;
		if(!cover[y])
		{
			cover[y]=1;
			int q=link[y];
			link[y]=x;
			if(!q || find(q)) return 1;
			link[y]=q;
		}
	}
	return 0;
}

int main()
{
	scanf("%d%d%d", &n, &m, &s);
	for(int i=1; i<=s; i++)
	{
		scanf("%d%d", &a, &b);
		add(a, b);
	}
	for(int i=1; i<=n; i++) memset(cover, 0, sizeof(cover)), find(i);
	for(int i=1; i<=m; i++) if(link[i]) ans++;
	printf("%d", ans);
	return 0;
}

你可能感兴趣的:(二分图,#,最大匹配(匈牙利算法))