1、二分图
2、匹配
如果G中每个顶点都是M饱和点,则称M为G的完美匹配。
3、匈牙利算法
1-P的路径长度必定为奇数,第一条边和最后一条边都不属于M。
2-将M和P进行异或操作(去同存异)可以得到一个更大的匹配M’。
3-M为G的最大匹配当且仅当不存在M的增广路径。
算法轮廓:
(1)置M为空
(2)找出一条增广路径P,通过异或操作获得更大的匹配M’代替M
(3)重复(2)操作直到找不出增广路径为止
4、代码模板
注意,如果手头并不是二分图,却要计算最大匹配数,就需要对现有的图进行拆点。就是将现有所有的点备份一份成为二分图的第二个点集,将现有图中的边全部转换为两个点集之间的边,如a->b就要转换成a->b',而如果现有图为无向图,我们就需要建立双向图来模拟无向图,如a->b就要转换成a->b',和b'->a两条边。最后匈牙利算法得出的最大匹配数则需要除二才是想要的答案。
接下来是公式:
①二分图的最大匹配数就是其最小点覆盖数
②二分图的最大独立集数=顶点数-最大匹配数
③二分图的最小路径覆盖数=顶点数-最大匹配数
其实都不难理解,可以理解后再用不需要死记硬背。
#include<vector>
using namespace std;
const int MAXC = 300;
const int T = 7*12;
int C , linker[T];
bool used[T];
vector<int> g[MAXC];
bool dfs(int c)
{
for( int i = 0 ; i < g[c].size() ; i++ )
{
int t = g[c][i];
if( !used[t] )
{
used[t] = true;
if( linker[t] == -1 || dfs(linker[t]) )
{
linker[t] = c;
return true;
}
}
}
return false;
}
int Hungary()
{
int res = 0;
for( int i = 0 ; i < T ; i++ )
linker[i] = -1;
for( int i = 0 ; i < C ; i++ )
{
for( int j = 0 ; j < T ; j++ )
used[j] = false;
if( dfs(i) )
res++;
}
return res;
}
这是从我poj2239的代码里截出来的,c和t的数据含义不用太在意。
注意,如果手头并不是二分图,却要计算最大匹配数,就需要对现有的图进行拆点。就是将现有所有的点备份一份成为二分图的第二个点集,将现有图中的边全部转换为两个点集之间的边,如a->b就要转换成a->b',而如果现有图为无向图,我们就需要建立双向图来模拟无向图,如a->b就要转换成a->b',和b'->a两条边。最后匈牙利算法得出的最大匹配数则需要除二才是想要的答案。
5、二分图最大匹配数的相关使用
首先来熟悉几个概念:
顶点覆盖:
在顶点集合中,选取一部分顶点,这些顶点能够把所有的边都覆盖了。这些点就是顶点覆盖集
最小顶点覆盖:
在所有的顶点覆盖集中,顶点数最小的那个叫最小顶点集合。
独立集:
在所有的顶点中选取一些顶点,这些顶点两两之间没有连线,这些点就叫独立集
最大独立集:
在左右的独立集中,顶点数最多的那个集合
路径覆盖:
在图中找一些路径,这些路径覆盖图中所有的顶点,每个顶点都只与一条路径相关联。
最小路径覆盖:
在所有的路径覆盖中,路径个数最小的就是最小路径覆盖了。
接下来是公式:
①二分图的最大匹配数就是其最小点覆盖数
②二分图的最大独立集数=顶点数-最大匹配数
③二分图的最小路径覆盖数=顶点数-最大匹配数
其实都不难理解,可以理解后再用不需要死记硬背。