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最早提出来的。
邻接矩阵
#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;
}