zoukankan      html  css  js  c++  java
  • 无权二分图最大匹配 HDU2063 匈牙利算法 || Hopcroft-Karp

    参考两篇比较好的博客 

    http://www.renfei.org/blog/bipartite-matching.html

    http://blog.csdn.net/thundermrbird/article/details/52231639###;

    最大匹配数为n     2*n个不同的点    n条不同的边

    匈牙利算法

    从未匹配的的点出发寻找   非匹配边大于匹配边的交替路(增广路)匹配边与非匹配边交换

    匈牙利算法模板(DFS,邻接矩阵版) 时间复杂度O(V*E)

     1 #include <stdio.h>
     2 #include <math.h>
     3 #include <string.h>
     4 #include <stdlib.h>
     5 #include <iostream>
     6 #include <sstream>
     7 #include <algorithm>
     8 #include <string>
     9 #include <queue>
    10 #include <map>
    11 #include <vector>
    12 using namespace std;
    13 const int maxn = 1005;
    14 const int maxm = 1e4+10;
    15 const int inf = 0x3f3f3f3f;
    16 const double epx = 1e-10;
    17 typedef long long ll;
    18 int n,m,k;
    19 int visit[maxn];
    20 int match[maxn];
    21 int a[maxn][maxn];
    22 bool found(int x)
    23 {
    24     for(int i=1;i<=m;i++)            //从右边的集合中找能与x进行匹配的点
    25     {
    26         if(a[x][i]==1&&visit[i]==0)   //x与i有联系且i没被查找过
    27         {
    28             visit[i]=1;
    29             if(match[i]==0||found(match[i]))  //第i个点还没有匹配 如果匹配了就看 与它匹配的那个点 能不能换个点完成匹配 把i空出来 如果可以i与x匹配
    30             {
    31                 match[i]=x;
    32                 return true;
    33             }
    34         }
    35     }
    36     return false;
    37 }
    38 int main()
    39 {
    40     while(scanf("%d",&k)!=EOF&&k)  //k条边
    41     {
    42         scanf("%d%d",&n,&m);      //左右两个集合的数量
    43         memset(a,0,sizeof(a));
    44         for(int i=1;i<=k;i++)
    45         {
    46             int x,y;
    47             scanf("%d %d",&x,&y);
    48             a[x][y]=1;               //有联系的点标记为1
    49         }
    50         memset(match,0,sizeof(match)); 
    51         int ans=0;
    52         for(int i=1;i<=n;i++)               //依次对左边集合中点进行匹配
    53         {
    54             memset(visit,0,sizeof(visit));  //清空访问标记数组 
    55             if(found(i))             //满足条件匹配数+1
    56                 ans++;
    57         }
    58         printf("%d
    ",ans);
    59     }
    60 }

    Hopcroft-Karp 算法

    复杂度 O(sqrt(n)*E)

    邻接表存图,vector 实现 ,vector 先初始化,然后加入边 , uN 为左端的顶点数,使用前赋值 (点编号 0 开始) 

    #include <bits/stdc++.h>
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define all(a) (a).begin(), (a).end()
    #define fillchar(a, x) memset(a, x, sizeof(a))
    #define huan printf("
    ")
    #define debug(a,b) cout<<a<<" "<<b<<" "<<endl
    #define ffread(a) fastIO::read(a)
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int MAXN = 1000+5;
    const int INF = 0x3f3f3f3f;
    vector<int>G[MAXN];
    int uN;
    int Mx[MAXN],My[MAXN];
    int dx[MAXN],dy[MAXN];
    int dis;
    bool used[MAXN];
    void init(int n)
    {
        uN=n;
        for(int i=0; i<n; i++)
            G[i].clear();
    }
    bool SearchP()
    {
        queue<int>Q;
        dis = INF;
        memset(dx,-1,sizeof(dx));
        memset(dy,-1,sizeof(dy));
        for(int i = 0 ; i < uN; i++)
            if(Mx[i]==-1)
            {
                Q.push(i);
                dx[i] = 0;
    
            }
        while(!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            if(dx[u] > dis)
                break;
            int sz = G[u].size();
            for(int i = 0; i < sz; i++)
            {
                int v = G[u][i];
                if(dy[v]==-1)
                {
                    dy[v] = dx[u] + 1;
                    if(My[v] == -1)
                        dis = dy[v];
                    else
                    {
                        dx[My[v]] = dy[v] + 1;
                        Q.push(My[v]);
                    }
                }
            }
        }
        return dis != INF;
    }
    bool DFS(int u)
    {
        int sz = G[u].size();
        for(int i = 0; i < sz; i++)
        {
            int v = G[u][i];
            if(!used[v] && dy[v] == dx[u] + 1)
            {
                used[v] = true;
                if(My[v] != -1 && dy[v] == dis)
                    continue;
                if(My[v] == -1 || DFS(My[v]))
                {
                    My[v] = u;
                    Mx[u] = v;
                    return true;
                }
            }
        }
        return false;
    }
    int MaxMatch()
    {
        int res = 0;
        memset(Mx,-1,sizeof(Mx));
        memset(My,-1,sizeof(My));
        while(SearchP())
        {
            memset(used,false,sizeof(used));
            for(int i = 0; i < uN; i++)
                if(Mx[i] == -1 && DFS(i))
                    res++;
        }
        return res;
    }
    int main()
    {
        int n,m,k;
        while(scanf("%d",&k)&&k)
        {
            scanf("%d%d",&m,&n);
            init(m);
            for(int i=0; i<k; i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                G[x-1].pb(y-1);
            }
            printf("%d
    ",MaxMatch());
        }
    }
  • 相关阅读:
    模拟扑克的洗发牌
    结构体 枚举类型
    return、break和continue
    clipboard.js操作剪贴版——一些移动端交互和兼容经验
    国外主机如何ICP备案
    js文件操作之——导出Excel (js-xlsx)
    深入浅出写一个多级异步回调从基础到Promise实现的Demo
    一个考察闭包的最基础的面试题
    shell常用命令及正则辅助日志分析统计
    node-webkit笔记
  • 原文地址:https://www.cnblogs.com/stranger-/p/8330950.html
Copyright © 2011-2022 走看看