邻接表版的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 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<queue> 7 #include<algorithm> 8 #include<map> 9 #include<iomanip> 10 #include<climits> 11 #include<string.h> 12 #include<cmath> 13 #include<stdlib.h> 14 #include<vector> 15 #define INF 1e7 16 #define MAXN 100010 17 #define maxn 1000010 18 #define Mod 1000007 19 #define N 1010 20 using namespace std; 21 typedef long long LL; 22 23 int n, m, k, a, b, ans; 24 bool vis[N]; 25 int match[N]; 26 vector<int> G[N]; 27 28 bool Search_path(int src) 29 { 30 for (int i = 0; i < G[src].size(); ++i) { 31 int v = G[src][i]; 32 if (!vis[v]) { 33 vis[v] = true; 34 if (match[v] == -1 || Search_path(match[v])) { 35 match[v] = src; 36 return true; 37 } 38 } 39 } 40 return false; 41 } 42 43 void init() 44 { 45 ans = 0; 46 for (int i = 0; i <= n; ++i) 47 G[i].clear(); 48 memset(match,-1,sizeof(match)); 49 } 50 51 int main() 52 { 53 while (cin >> n >> m) { 54 init(); 55 cin >> k; 56 for (int i = 0; i < k; ++i) { 57 cin >> a >> b; 58 a--, b--; 59 G[a].push_back(b); 60 } 61 for (int i = 0; i < n; ++i) { 62 memset(vis,0,sizeof(vis)); 63 if (Search_path(i)) 64 ans++; 65 } 66 cout << ans << endl; 67 } 68 return 0; 69 }
附上模板
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<int> G[__maxNodes]; /* G[i] 存储顶点 i 出发的边的编号 */ 14 vector<Edge> edges; 15 typedef vector<int>::iterator iterator_t; 16 int num_nodes; 17 int num_left; 18 int num_right; 19 int num_edges;
DS
1 queue<int> 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<num_left; ++i) { 9 if (matching[i] == -1) { 10 while (!Q.empty()) Q.pop(); 11 Q.push(i); 12 prev[i] = -1; // 设 i 为路径起点 13 bool flag = false; // 尚未找到增广路 14 while (!Q.empty() && !flag) { 15 int u = Q.front(); 16 for (iterator_t ix = G[u].begin(); ix != G[u].end() && !flag; ++ix) { 17 int v = edges[*ix].to; 18 if (check[v] != i) { 19 check[v] = i; 20 Q.push(matching[v]); 21 if (matching[v] >= 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 }
BFS
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 }
DFS
时间: 2024-10-04 07:17:15