首先需要知道什么是二分图
定理:设G=<V,E>为一个简单无向图,G为二部图的充要条件是G中的每一个圈的长度都是偶数
二分图的判定:
染色法:假设DFS初始化点A涂黑色,与它相邻的点就涂白色。如果搜到某一点u的相邻点v已经涂色并且与u同色,就不可能是二分图啦
匹配:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配
最大匹配:包含边数最多的匹配
完美匹配(完备匹配):所有点都在匹配边上的匹配
最佳匹配:如果G为加权二分图,则权值和最大的完备匹配称为最佳匹配
如下图
匈牙利算法用来求二分图的最大匹配
用到的一些概念
饱和点:结点u被称为M的饱和点,当且仅当有杆e属于M匹配结点u;否则结点u称为非饱和点
交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边........形成的路径叫交替路
增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发点不算),则这条交替路称为增广路
如下图是一条增广路
由增广路的定义可以推出下述三个结论
1、P的路径长度必定为奇数,第一条边和最后一条边都不属于M
2、P经过取反操作可以得到一个更大的匹配M’
3、M为G的最大匹配当且仅当不存在相对于M的增广路径
算法步骤
1、初始化M为空
2、找一条增广路经P,通过取反操作获得更大的匹配M’代替M
3、重复2操作直到找不出增广路经为止
时间复杂度 O(V*E)
代码实现
//邻接矩阵存图
bool dfs(int u)
{
for(int v=1;v<=n;v++)
{
if(my_map[u][v]&&!vis[v])//u-v边存在,结点v不在M中
{
vis[v]=true;
if(match[v]==-1||dfs(match[v])) //v是非饱和点,或者v是饱和点,看看match[v]是否能
//腾出来v,让v去匹配点u
{
match[v]=u;
return true;
}
}
}
return false;
}
int main()
{
int sum=0; //匹配数
memset(match,-1,sizeof match);
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof vis);
if(dfs(i)) sum++;
}
}