题解 P3386 【【模板】二分图匹配】

二分图匹配的常用算法有匈牙利算法和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返回值更新答案。

posted @ 2018-10-25 16:16  Ilverene  阅读(158)  评论(0编辑  收藏  举报