• graph | hungary


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

    若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 }

    时间复杂度是O(VE),空间复杂度感觉O(V)就行了啊,为什么其他人都说是O(V+E)?.

  • 相关阅读:
    callable函数,检查对象是否可调用
    eval函数的一些用法
    divmod函数使用
    sorted(x, reverse=True)
    列表、元组、字典空格的几种移除方法
    约瑟夫环问题(通过观察得出递推式从而建立递归求解)
    快速幂算法(二分思想减少连乘次数)
    素数筛(埃氏筛法与欧拉筛)
    KMP算法的详细解释
    对于线性代数的形象化理解(1)
  • 原文地址:https://www.cnblogs.com/linyx/p/4069088.html
Copyright © 2020-2023  润新知