二分匹配的过程:
算法的核心是找增广路径的过程 --- DFS
对于每个可以与u匹配的顶点v,假如它未被匹配,可以直接用v与u匹配;
如果v已与顶点w匹配,那么只需调用dfs(w)来求证w是否可以与其它顶点匹配,如果dfs(w)返回1的话,仍可以使v与u匹配;如果dfs(w)返回0,则检查u的下一个邻接点。
在dfs时,要标记访问过的顶点(book[i] = 1),以防死循环和重复计算;每次在主过程中开始一次dfs前,所有的顶点都是未标记的。
主过程只需对每个X部的顶点调用dfs,如果返回一次1,就对最大匹配数加一;一个简单的循环就求出了最大匹配的数目。
相关定义:
1、最大匹配数:最大匹配的匹配边的数目
2、最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择
3、最大独立集:选取最多的点,使任意所选两点均不相连
4、最小路径覆盖数:对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。
5、定理1:最大匹配数 = 最小点覆盖数(这是 Konig 定理)
6、定理2:最大独立集 = 顶点数 - 最小点覆盖数
7、定理3:最小路径覆盖数 = 顶点数 - 最大匹配数
二分图的最大团
1、定义:对于一般图来说,团是一个顶点集合,且由该顶点集合诱导的子图是一个完全图,简单说,就是选出一些顶点,这些顶点两两之间都有边。最大团就是使得选出的这个顶点集合最大。对于二分图来说,我们默认为左边的所有点之间都有边,右边的所有顶点之间都有边。那么,实际上,我们是要在左边找到一个顶点子集X,在右边找到一个顶点子集Y,使得X中每个顶点和Y中每个顶点之间都有边。
2、方法:二分图的最大团=补图的最大独立集。
3、补图的定义是:对于二分图中左边一点x和右边一点y,若x和y之间有边,那么在补图中没有,否则有。
4、这个方法很好理解,因为最大独立集是两两不相邻,所以最大独立集的补图两两相邻。
模板:
#include<stdio.h>
#include<string.h>
int m,n,e[110][110],match[110],book[110];
int dfs(int u)
{
int i;
for(i = 1; i <= n; i ++)
{
if(book[i] == 0 && e[u][i] == 1)
{
book[i] = 1;
if(match[i] == 1 || dfs(match[i]))
{
match[i] = u;
return 1;
}
}
}
return 0;
}
int main()
{
int i,x,y,sum;
while(scanf("%d%d",&n,&m) != EOF)
{
sum = 0;
memset(e,0,sizeof(e));
memset(match,0,sizeof(match));
for(i = 1; i <= m; i ++)
{
scanf("%d%d",&x,&y);
e[x][y] = 1;
}
for(i = 1; i <= n; i ++)
{
memset(book,0,sizeof(book));
if(dfs(i))
sum ++;
}
printf("%d\n",sum);
}
return 0;
}