码迷,mamicode.com
首页 > 其他好文 > 详细

graph | hungary

时间:2014-11-02 13:45:21      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:style   blog   io   color   ar   os   for   sp   div   

匈牙利算法,求二分图最大匹配。

若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。(M为一个匹配)

由增广路的定义可以推出下述三个结论:

  • P的路径长度必定为奇数,第一条边和最后一条边都不属于M。所以Line 25-27从first part出发,不从二分图的另一部分出发。Line 12实现了交替出现的逻辑;node->neig匹配,当且仅当neig没有被其他点匹配,或者neig被first中的其他点matches[neig]匹配,并且从matches[neig]能够找到一条增广路径。这里就实现了交替的逻辑了。
  • 将M和P进行异或操作(去同存异)可以得到一个更大的匹配M’。这是因为,属于M的边和不属于M的边交替出现,且第一和最后一条边都不属于M,所以增广路径中,不属于M的边比属于M的边多1,去同存异之后,一定会得到一个更大的匹配(加1了)。Line 13实现的是去同存异的逻辑。如果从node到neig存在一条增广路径,那么中间这些相同的部分直接省略。
  • M为G的最大匹配当且仅当不存在M的增广路径。
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <vector>
 4 
 5 using namespace std;
 6 
 7 bool augment(vector<vector<int> > &adj, int node, 
 8         vector<bool> &visited, vector<int> &matches) {
 9     for (auto neig : adj[node]) {
10         if (!visited[neig]) {
11             visited[neig] = true;
12             if (matches[neig] == -1 || augment(adj, matches[neig], visited, matches)) {
13                 matches[neig] = node;
14                 return true;
15             }
16         }
17     }
18     return false;
19 }
20 
21 int hungary(vector<vector<int> > &adj, vector<int> &first) {
22     vector<bool> visited;
23     vector<int> matches(adj.size(), -1); 
24     int count = 0;
25     for (auto f : first) {
26         visited.assign(adj.size(), false);
27         if (augment(adj, f, visited, matches)) {
28             count++;
29         }
30     }
31     for (int i = 0; i < adj.size(); ++i) {
32         cout << i << "<->" << matches[i] << endl;
33     }
34     return count;
35 }
36 
37 int main(int argc, char** argv) {
38     freopen("input.txt", "r", stdin);
39     int first, n, m;
40     cin >> n >> first >> m;
41     vector<vector<int> > adj(n);
42     vector<int> left;
43     for (int i = 0; i < first; ++i) {
44         int l;
45         cin >> l;
46         left.push_back(l);
47     }
48     for (int i = 0; i < m; ++i) {
49         int n1, n2;
50         cin >> n1 >> n2;
51         adj[n1].push_back(n2);
52         adj[n2].push_back(n1);
53     }
54 
55     cout << hungary(adj, left) << endl;
56     return 0;
57 }

假设左边结点个数为n, 右边结点个数为m,这里用了visited来确保右边的点不会重复访问,时间复杂度还是是O(nmn),如果把邻接表用list而不是vector的话,访问过的右边结点删去,那么开销可以在O(nm)了。因为右边结点只需访问一次。

空间复杂度是O(m+n)。

graph | hungary

标签:style   blog   io   color   ar   os   for   sp   div   

原文地址:http://www.cnblogs.com/linyx/p/4069088.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!