二分图匹配的常用算法有匈牙利算法和Dinic算法,这里只讨论前者。
所谓二分图,就是指一类能够被分成两半的图,其中每一半的点都没有任何边连接。
而二分图的匹配,就是指二分图的一个子图中任意两条边都没有公共点。(这个子图就是一个匹配)
本题求的是最大匹配数,顾名思义,就是匹配中边数最大为多少。
匈牙利算法的本质是贪心。我们每一次都找一条增广路,然后再取反寻找比当前匹配更大的匹配。没有增广路就结束。
百度百科是这样定义增广路的:
若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径(举例来说,有A、B集合,增广路由A中一个点通向B中一个点,再由B中这个点通向A中一个点……交替进行)。
实现
我们使用DFS实现匈牙利算法。
inline bool dfs(int u){
for(int v=1;v<=m;v++)
if(t[u][v]&&!vis[v]){
vis[v]=1;
if(cy[v]==-1||dfs(cy[v])){
cx[u]=v;cy[v]=u;
return 1;
}
}
return 0;
}
这段代码寻找从u出发的增广路。
首先我们先枚举与u有连接的所有节点。
然后如果未访问就进去逛一逛。
如果发现这个节点还没有被匹配或者说存在从它出发的增广路,那就跳进去。回溯时返回true,表示存在从u出发的增广路。
如果逛了一圈一个节点都不行,那就返回false,因为没有从u出发的增广路。
for(int i=0;i<=nx;i++)
if(cx[i]==-1){
memset(visit,false,sizeof(visit)) ;
ans += dfs(i);
}
在主程序中我们过一遍所有点,如果当前未匹配就dfs一下,然后根据dfs返回值更新答案。