月老的难题,这一题是最大匹配问题,求最大匹配的常见方法有贪心(对出度的贪心),最大流算法(加个源点和汇点),在这是匈牙利算法(寻找增广路,每找到一个增广路,配对加一)
这道题我是用匈牙利算法写的(刚学的),下面我说下我对这个算法的理解,在做这题前,我没用过邻接表存过图,就因为我想写下邻接表,这道题一搁搁了好几天。今天第一次写时,还是老习惯用邻接矩阵(菜呀),写好之后,运行了一下,果断超时。那只好老老实实地去写邻接表吧,幸亏以前看过,看着一个同学的模板,写了下邻接表,存图的问题解决了,那接着就得解决匈牙利算法:匈牙利算法的核心就是寻找增广路,增广路,在我理解里它就是交错路径,而交错路径是什么呢?我是这样理解的,假如有两个集合A,B,A集合里一个点a1,去匹配B集合里的一点b1,而B集合里点b1早已和A中的a2匹配,如果B中有b2可以和a2匹配的,那么我们就让它与a2与b2匹配,如果b2在A中已经有匹配a3,那么我们再让a3去找匹配…………就这样直到找到一个未匹配的点,这就是一条交错路径,我就是这样理解的。
用最大流和贪心去做这道题,代码我没写呢,只是从网上看了些东西,知道了这些思路,改天再写,代码有些凌乱。
#include<stdio.h>
#include<string.h>
#define N 510
#define K 10005
struct
{
int head;
}V[N];
struct
{
int v,next;
}E[K];
int top,match[N],used[N];
void Add_Edge(int u,int v)
{
E[top].v=v;
E[top].next=V[u].head;
V[u].head=top++;
}
int DFS(int u)
{
int i,v;
for(i=V[u].head;i!=-1;i=E[i].next)
{
v=E[i].v;
if(!used[v])
{
used[v]=1;
if(!match[v]||DFS(match[v]))
{
match[v]=u;
return 1;
}
}
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
top=0;
memset(match,0,sizeof(match));
memset(V,-1,sizeof(V));
int k,count,n,u,v,i;
scanf("%d%d",&n,&k);
for(i=0;i<k;i++)
{
scanf("%d%d",&u,&v);
Add_Edge(u,v);
}
count=0;
for(i=1;i<=n;i++)
{
memset(used,0,sizeof(used));
if(DFS(i))
count++;}
printf("%d\n",count);}
}