匈牙利算法

匈牙利算法一般应用于二分图的匹配问题。

大家可以在网上搜索一篇匈牙利算法之找妹子的文章,个人认为他写得很精彩~

算法如下:

bool find(int a) {
    for (int i = 1; i <= n2; i++) {
        if (data[a][i] == 1 && !state[i]) { //如果节点i与a相邻并且未被查找过
            state[i] = true; //标记i为已查找过
            if (result[i] == 0 //如果i未在前一个匹配M中
            || find(result[i])) { //i在匹配M中,但是从与i相邻的节点出发可以有增广路
                result[i] = a; //记录查找成功记录
                return true; //返回查找成功
            }
        }
    }
    return false;
}
int main() {
   for (int i = 1; i <= n1; i++) {
        memset(state,0,sizeof(state)); //清空上次搜索时的标记
        if (find(i)) ans++; //从节点i尝试扩展
    }
    printf("%d\n",ans);
    return 0;
}

 

 

二分图
无向图中顶点可分为两个不相交集合X和Y,使得图中每一条边都分别连接X、Y中的顶点。
同一顶点集合内部无边。

二分图的判定
染色法:
对任一未染色顶点染色;
若其相邻顶点未染色,染另一种色;
若相邻顶点已染不同色,继续;
若相邻顶点已染同一色,不是二分图,终止;
使用BFS/DFS重复上述过程。
任何无向无环图均为二分图,如树。


增广路径
从一个未匹配点出发,依次交替经过非匹配边、匹配边、非匹配边…,若途经另一个未匹配点,则该路径称为增广路径。

增广路径的特性
有奇数条边,且非匹配边比匹配边多一条。
起点和终点为未匹配点,其他均为匹配点。
所有第奇数条边都不在原匹配中,所有第偶数条边恰相反。
增广路径取反:
若将所有第偶数条边从原匹配移除,并加入所有第奇数条边,则可使匹配数 + 1.

 

思路
寻找增广路径,并通过增广路径取反增加匹配数。
不断进行,直到无法找到新的增广路径。
初始时,任一条边均可做增广路径。

不同的顺序可能导致不同的匹配,但最终匹配数相同(最大)。

 

增广路径的寻找
从一个未匹配点出发,DFS或BFS均可,到达其他未匹配点即终止。
限制:若经过某个匹配点,则接下来必须经过其匹配边。
保证未匹配边、匹配边依次交替。
BFS对于大型稀疏图性能更高,但DFS代码简洁,不易出错。

 

 

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

 


 


 

 

posted @ 2015-12-27 13:46  xfei.zhang  阅读(272)  评论(0编辑  收藏  举报