zoukankan      html  css  js  c++  java
  • 匈牙利算法

    匈牙利算法是众多用于解决线性任务分配问题的算法之一,是用来解决二分图最大匹配问题的经典算法,可以在多项式时间内解决问题,由美国数学家Harold Kuhn 于1955年提出。此算法之所以被称作匈牙利算法是因为算法很大一部分是基于以前匈牙利数学家Dénes Kőnig和Jenő Egerváry的工作之上创建起来的.

    定义

    未盖点:设Vi是图G的一个顶点,如果Vi 不与任意一条属于匹配M的边相关联,就称Vi 是一个未盖点。 交错路:设P是图G的一条路,如果P的任意两条相邻的边一定是一条属于M而另一条不属于M,就称P是一条交错路。 可增广路:两个端点都是未盖点的交错路叫做可增广路。

    伪代码

    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的对应项出有可增广路)
                匹配数++;
        }
        输出 匹配数;
    }

    个人认为,匈牙利算法其实就是Ford-Fulkerson:dfs增广路最大流算法的提取和简化。 观察Ford-Fulkerson最大流dfs增广路的过程,因为二分图的特殊性质,这条增广路其实就是匈牙利算法中要求的交错路。 并且我们知道是Ford-Fulkerson最大流的时间复杂度为O(E*Maxflow),而二分图匹配中最大流不超过V,所以时间复杂度是O(VE)。

    C++实现

    //入门题:USACO 4.2.2 The Perfect Stall(POJ 1274)
    const int MAXV = 405;                   //N1+N2
    struct MaximumMatchingOfBipartiteGraph{
        int vn1, vn2;
        vector  adj[MAXV];
        void init(int n1, int n2){          //二分图两点集点的个数
            vn1 = n1;
            vn2 = n2;
            for (int i = 0; i <= n1+n2; i ++)     adj[i].clear();
        }
        /** 一定要注意n1点标号1~n1,n2点要把标号转换为n1+1~n1+n2**/
        void add_uedge(int u, int v){
            adj[u].push_back(v);    adj[v].push_back(u);
        }
        bool vis[MAXV];
        int mat[MAXV];                      //记录已匹配点的对应点
        bool cross_path(int u){
            for (int i = 0; i < (int)adj[u].size(); i ++){
                int v = adj[u][i];
                if (!vis[v]){
                    vis[v] = true;
                    if (mat[v] == 0 || cross_path(mat[v])){
                        mat[v] = u;
                        return true;
                    }
                }
            }
            return false;
        }
        int hungary(){
            mem(mat, 0);
            int match_num = 0;
            for (int i = 1; i <= vn1; i ++){
                mem(vis, 0);
                if (cross_path(i)){
                    match_num ++;
                }
            }
            return match_num;
        }
    }match;
    
    int main(){
    	//freopen("test.in", "r", stdin);
    	//freopen("test.out", "w", stdout);
        int n, m;
        while(scanf("%d %d", &n, &m) != EOF){
            match.init(n, m);
            for (int i = 1; i <= n; i ++){
                int num;
                scanf("%d", &num);
                for (int j = 0; j < num; j ++){
                    int tmp;
                    scanf("%d", &tmp);
                    match.add_uedge(i, n+tmp);
                    /** 一定要注意n1点标号1~n1,n2点要把标号转换为n1+1~n1+n2**/
                }
            }
            printf("%d
    ", match.hungary());
        }
    	return 0;
    }
  • 相关阅读:
    JQuery文档插件
    MVC3下使用Jquery异步提交数据!
    不错的在线客服插件~
    让火狐和chorme浏览器支持uploadify带Cookie上传
    Socket服务器代码
    Winform控件加载时闪烁的解决方案!
    MVC3 无刷新验证码
    网络时间同步
    关于多线程委托的控件操作
    c# 利用反射动态给实体类对象赋值
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114282.html
Copyright © 2011-2022 走看看