邻接表版的DFS形式的二分匹配
增广路求最大匹配数
匈牙利算法的要点如下
-
从左边第 1 个顶点开始,挑选未匹配点进行搜索,寻找增广路。
- 如果经过一个未匹配点,说明寻找成功。更新路径信息,匹配边数 +1,停止搜索。
- 如果一直没有找到增广路,则不再从这个点开始搜索。事实上,此时搜索后会形成一棵匈牙利树。我们可以永久性地把它从图中删去,而不影响结果。
-
由于找到增广路之后需要沿着路径更新匹配,所以我们需要一个结构来记录路径上的点。DFS 版本通过函数调用隐式地使用一个栈,而 BFS 版本使用
prev
数组。
详细介绍http://www.renfei.org/blog/bipartite-matching.html
bool 寻找从k出发的对应项出的可增广路{ while (从邻接表中列举k能关联到顶点j) { if (j不在增广路上) { 把j加入增广路; if (j是未盖点 或者 从j的对应项出发有可增广路) { 修改j的对应项为k; 则从k的对应项出有可增广路,返回true; } } } 则从k的对应项出没有可增广路,返回false;}void 匈牙利hungary(){ for i->1 to n { if (则从i的对应项出有可增广路) 匹配数++; } 输出 匹配数;}
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include
附上模板
1 // 顶点、边的编号均从 0 开始 2 // 邻接表储存 3 4 struct Edge 5 { 6 int from; 7 int to; 8 int weight; 9 10 Edge(int f, int t, int w):from(f), to(t), weight(w) {}11 };12 13 vector G[__maxNodes]; /* G[i] 存储顶点 i 出发的边的编号 */14 vectoredges;15 typedef vector ::iterator iterator_t;16 int num_nodes;17 int num_left;18 int num_right;19 int num_edges;
1 queue Q; 2 int prev[__maxNodes]; 3 int Hungarian() 4 { 5 int ans = 0; 6 memset(matching, -1, sizeof(matching)); 7 memset(check, -1, sizeof(check)); 8 for (int i=0; i= 0) { // 此点为匹配点22 prev[matching[v]] = u;23 } else { // 找到未匹配点,交替路变为增广路24 flag = true;25 int d=u, e=v;26 while (d != -1) {27 int t = matching[d];28 matching[d] = e;29 matching[e] = d;30 d = prev[d];31 e = t;32 }33 }34 }35 }36 Q.pop();37 }38 if (matching[i] != -1) ++ans;39 }40 }41 return ans;42 }
1 int matching[__maxNodes]; /* 存储求解结果 */ 2 int check[__maxNodes]; 3 4 bool dfs(int u) 5 { 6 for (iterator_t i = G[u].begin(); i != G[u].end(); ++i) { // 对 u 的每个邻接点 7 int v = edges[*i].to; 8 if (!check[v]) { // 要求不在交替路中 9 check[v] = true; // 放入交替路10 if (matching[v] == -1 || dfs(matching[v])) {11 // 如果是未盖点,说明交替路为增广路,则交换路径,并返回成功12 matching[v] = u;13 matching[u] = v;14 return true;15 }16 }17 }18 return false; // 不存在增广路,返回失败19 }20 21 int hungarian()22 {23 int ans = 0;24 memset(matching, -1, sizeof(matching));25 for (int u=0; u < num_left; ++u) {26 if (matching[u] == -1) {27 memset(check, 0, sizeof(check));28 if (dfs(u))29 ++ans;30 }31 }32 return ans;33 }