二分图的重匹配,说白了就说一对多的匹配。还是匈牙利算法,一般都是给出两个集合,然后让你对这两个集合进行匹配,但是其中一个集合是可以多次匹配的,但是匹配的次数是有限的(假设其中一个i的上限是limit[i]),和这个i匹配的个数就不能超过limit[i],而且每次匹配都会二分一些东西,来确定这两个之间能不能匹配。基本思路就是这样的。
来道例题:POJ 3189——Steady Cow Assignment
题目大意是说:给你n头牛和m个牛棚,每个牛对每个牛棚都有一个喜爱值,让你来确定把所有的牛都赶进牛棚,而且每个牛棚中的牛对这个牛棚的喜爱值差值最小,求出这个最小差值。
思路
一个牛是只能进一个牛棚的,而一个牛棚可以装很多牛,但是这题每个牛棚可以装牛的数量上限给出了。那么我们就可以对牛和牛棚进行二分图匹配,我们来枚举差值,通过枚举这个区间的最大值和最小值来判断这个牛和牛棚之间能不能匹配。
AC代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
const int N=1010;
int line[N][50];
int ma[50][N];
int b[50];
int sum[N];
int vis[N];
int n,m;
int low,high;
int erft(int u)
{
for(int i=1;i<=m;i++)
{
if(!vis[i]&&line[u][i]<=high&&line[u][i]>=low)
{
vis[i]=1;
if(sum[i]<b[i])
{
ma[i][sum[i]++]=u;
return 1;
}
else
{
for(int j=0;j<=b[i];j++)
{
if(erft(ma[i][j]))
{
ma[i][j]=u;
return 1;
}
}
}
}
}
return 0;
}
int fin()
{
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(!erft(i))
{
return 0;
}
}
return 1;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int w;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&w);
line[i][w]=j;
}
}
for(int i=1;i<=m;i++)
{
scanf("%d",&b[i]);
}
int ans=1e8;;
low=high=1;
while(low<=high&&high<=m)
{
if(fin())
{
ans=min(high-low+1,ans);
low++;
}
else
{
high++;
}
}
printf("%d\n",ans);
}
return 0;
}