zoukankan      html  css  js  c++  java
  • 匈牙利算法学习 (名词理解 + 简单说明)

    二分图的定义 

        二分图是这样一个图,它的顶点可以分类两个集合X和Y,所有的边关联在两个顶点中,恰好一个属于集合X,另一个属于集合Y。

    未盖点  :设Vi是图G的一个顶点,如果Vi 不与任意一条属于匹配M的边相关联,就称Vi 是一个未盖点。

    交错路:设P是图G的一条路,如果P的任意两条相邻的边一定是一条属于M而另一条不属于M,就称P是一条交错路。

    可增广路:两个端点都是未盖点交错路叫做可增广路。

    最大匹配: 图中包含边数最多的匹配称为图的最大匹配。 

    完美匹配: 如果所有点都在匹配边上,称这个最大匹配是完美匹配。

    最小覆盖:在一个二分图上用最少的点(x 或 y 集合的都行),让每条连接两个点集的边都至少和其中一个点关联。根据konig定理:二分图的最小顶点覆盖数等于最大匹配数。

    最小路径覆盖:用尽量少的不相交简单路径(连着n条边)覆盖有向无环图G的所有结点,且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次);解决此类问题可以建立一个二分图模型。把所有顶点i拆成两个:X结点集中的i和Y结点集中的i',如果有边i->j,则在二分图中引入边i->j',设二分图最大匹配为m,则结果就是n-m。

    最大独立集问题:在N个点的图G中选出m个点,使这m个点两两之间没有边(没有某种关系).求m最大值.如果图G满足二分图条件,则可以用二分图匹配来做.最大独立集点数 = N - 最大匹配数

    伪代码:

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

    二分图最大匹配问题的匈牙利算法:

    #include<iostream>
    using namespace std;
    const int Max = 405;
    
     
    
    int n, m;                       //  二分图中x和y中点的数目
    int link[Max];                  //  link[x]记录当前与y节点相连的x的节点。
    bool map[Max][Max], vis[Max];   //  map[i][j]记录连接x和y的边,如果i和j之间有边则为1,否则为0。
    
     
    
    bool dfs(int u){                //  dfs实现,u表示现在在寻求匹配y的点x。
        for(int i = 1; i <= m; i ++)
            if(!vis[i] && map[u][i]){
                vis[i] = true;
                if(link[i] == -1 || dfs(link[i])){    //  条件:点i还没匹配,或者link[i]找到新的匹配。
                    link[i] = u;
                    return true;
                }
            }
        return false;
    }
    
     
    
    int MaxMatch(){
    
        int i,num = 0;
    
        memset(link, -1, sizeof(link));
    
        for(i = 1;i <= n; i ++){
    
            memset(vis, 0, sizeof(vis));
    
            if(bfs(i)) num++;
    
        }
    
        return num;
    
    }

    算法思想:

    算法的思路是不停的找增广轨,并增加匹配的个数,增广轨顾名思义是指一条可以使匹配数变多的路径,在匹配问题中,增广轨的表现形式是一条"交错轨",也就是说这条由图的边组成的路径,它的第一条边是目前还没有参与匹配的,第二条边参与了匹配,第三条边没有..最后一条边没有参与匹配,并且始点和终点还没有被选择过.这样交错进行,显然他有奇数条边.那么对于这样一条路径,我们可以将第一条边改为已匹配,第二条边改为未匹配...以此类推.也就是将所有的边进行"反色",容易发现这样修改以后,匹配仍然是合法的,但是匹配数增加了一对.另外,单独的一条连接两个未匹配点的边显然也是交错轨.可以证明,当不能再找到增广轨时,就得到了一个最大匹配.这也就是匈牙利算法的思路.

  • 相关阅读:
    用Docker执行Percona Server
    Java基础 笔记(七)
    VC与JavaScript交互(三) ———— JS调用C++
    4456: [Zjoi2016]旅行者|分治+最短路
    Swift语法学习之 方法
    JavaScript学习笔记二
    Latex 制作积分规则表格
    向MapReduce转换:计算共现关系
    王立平--switch case
    组队训练1 回放
  • 原文地址:https://www.cnblogs.com/jackge/p/3058489.html
Copyright © 2011-2022 走看看