【题目来源】:http://acm.hdu.edu.cn/showproblem.php?pid=2063
【题意】
女生与男生配对,找出最多的配对的数目、
【思路】
按照二分图匹配里的增广路的思想,递归模拟就可以了。
增广路的大致思想是:
假设有那么一个图:
其中已经描述了对应关系,那么模拟一下匹配的过程。(全程按照代码来讲)
首先:
对A,遍历右边,找到有联系的第一个是a,那么相连,并且把linked[a]=A,也就是说与a已连接的是A
接着:
对B,遍历右边,找到有关系的第一个点a,但是a已经是A的人了,根据增广路的思想,看下,A能不能换一个人,也就是说先把vis[a]打个标记,说明该点处于待定状态,结果,A只有一个可连接的,所以,不能换,所以,对B,继续遍历右边,找到第二个可以连接的点,也就是b,连接
再然后:
对C,遍历右边,发现b是和C有关系的,那么发先linked[b]==B,也即是说b已经是B的人了,按照增广路的思想,问一下B能不能换人,然后重复刚才对B的操作,发先,并不能,于是,继续遍历右边,最终连上了c
最后:
对D,他只有唯一的对象c被C占了,那么问下C能不能换人,然后重复上面的操作,发现,并不能,所以,他没得选。。
最终结果智能匹配到三组。
这是按照代码讲解的。。。
【代码】
#include<map>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
int k,n,m;
const int maxn=500+10;
int relax[maxn][maxn];//存下最初的相互之间的关系
int linked[maxn];//针对女生来说,已经被谁匹配到了
bool vis[maxn];//用于增广路当中往上递归(验证是否能够让位)的过程中,处于待定的点
bool find(int x)//递归
{
for(int i=1;i<=m;i++)
{
if(relax[x][i]&&!vis[i])
{
vis[i]=1;
if(!linked[i]||find(linked[i]))
{
linked[i]=x;
vis[i]=0;//消除标记
return 1;
}
}
}
return 0;
}
int main()
{
while(~scanf("%d",&k))
{
if(k==0) break;
scanf("%d%d",&n,&m);
memset(relax,0,sizeof(relax));
while(k--)
{
int x,y;
scanf("%d%d",&x,&y);
relax[x][y]=1;
}
memset(linked,0,sizeof(linked));
int ans=0;
for(int i=1;i<=n;i++)
{
if(find(i))
ans++;
}
printf("%d\n",ans);
}
}
当然,既然是题中给出的是点与点之间的关系,那么也可以用邻接表进行存图。
【代码】
#include<map>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
int k,n,m;
const int maxn=500+10;
int linked[maxn];
bool vis[maxn];
struct line
{
int to,next;
}relax[maxn*maxn];
int first[maxn];
bool find(int x)
{
for(int i=first[x];i!=-1;i=relax[i].next)
{
if(!vis[relax[i].to])
{
vis[relax[i].to]=1;
if(!linked[relax[i].to]||find(linked[relax[i].to]))
{
linked[relax[i].to]=x;
vis[relax[i].to]=0;
return 1;
}
}
}
return 0;
}
int main()
{
while(~scanf("%d",&k))
{
if(k==0) break;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
first[i]=-1;
int tot=0;
while(k--)
{
int x,y;
scanf("%d%d",&x,&y);
relax[tot].to=y;
relax[tot].next=first[x];
first[x]=tot++;
}
memset(linked,0,sizeof(linked));
int ans=0;
for(int i=1;i<=n;i++)
{
if(find(i))
ans++;
}
printf("%d\n",ans);
}
}