zoukankan      html  css  js  c++  java
  • uestc SOUND OF DESTINY

    邻接表版的DFS形式的二分匹配

    增广路求最大匹配数

    匈牙利算法的要点如下

    1. 从左边第 1 个顶点开始,挑选未匹配点进行搜索,寻找增广路。

      1. 如果经过一个未匹配点,说明寻找成功。更新路径信息,匹配边数 +1,停止搜索。
      2. 如果一直没有找到增广路,则不再从这个点开始搜索。事实上,此时搜索后会形成一棵匈牙利树。我们可以永久性地把它从图中删去,而不影响结果。
    2. 由于找到增广路之后需要沿着路径更新匹配,所以我们需要一个结构来记录路径上的点。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
  • 相关阅读:
    转:浅谈Linux的内存管理机制
    (转)Redis
    检测socket链接是否断开
    linux C 中的volatile使用
    LINUX 下 ipv6 socket 编程
    linux signal 列表
    Linux下异常信号
    linux signal
    转: 关于Linux常用的二进制文件分析方法
    IOI2020 题解
  • 原文地址:https://www.cnblogs.com/usedrosee/p/4294787.html
Copyright © 2011-2022 走看看