算法导论——二分图最大匹配

二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

这是个逗比博主写的匈牙利算法和KM算法

通俗点讲:就是将图中的节点分到两个集合中,满足:只存在由一个集合中的点指向另一个集合中的点的边。(也就是说两个集合中点不互通)

二分图的一个等价定义是:不含有「含奇数条边的环」的图

因此,如果存在环的话,环的边数只能是偶数,这样才能均分到两个集合中。如果是奇数一定不是二分图。

匹配
边指向一个点成为匹配。已匹配的点不能够再次匹配。
如图,基数为2的匹配

匹配

最大匹配
最大基数的匹配。
上面图中最大匹配为:

最大匹配

完美匹配
两个集合中的点,两两匹配。点都是匹配点,但是边不一定是匹配边

判断是否是二分图

使用深度优先搜索,从任意一点开始遍历,对一点进行染色,其相邻如果为染色则染为不同的颜色,如果存在已染色且染色和相邻节点相同,那么表示存在环路(因为环路所以才被染色),且环路边数为奇数(因为相同颜色),那么不是二分图。

匈牙利算法

寻找二分图中的最大匹配

假设:

  1. 二分图中所有的节点都在一个环上,或者一条通路上。
    那么我们只要找到这条最长的路径即可算出最大匹配。
    比如最长路径为4,那么最大匹配为2
  2. 假设二分图是完美匹配
    这样我们需要遍历每一个点,然后对已经匹配过的点进行标记。就自然的获得总点数/2的最大匹配

但实际中二分图中并不是单纯的一个环或者是完美匹配。二是两者结合,比如存在几对点的完美匹配,和几个环,或者几个通路。而且通路和环又相互叠加。

解决方法也是上面两种假设的解决方法的叠加:寻找最长通路(路径)和遍历

在二分图中找到的路径总是在两个集合中跳:类似于,左->右->左->右....
因为匹配的概念是左右两个集合中的点一一对应。所以这条路径中的边一定也是匹配边和非匹配边相互交叉。
比图,第二个右,如果左->右是一条匹配边,那么右->左就是非匹配边。
这种路径叫做增广路径

在匈牙利算法中,我们一边寻找最长增广路径,一边去遍历那些可能的一一匹配的点。

struct Edge
{
    int from;
    int to;
};



int hungarian_dfs()
{
    int counts=0;
   //用来记录二分图中的节点数目
    int maxNode=10;
    //用来记录节点是否已经匹配过了
    vector<int> matched(maxNode,-1)
    //用来记录在一个递归增长增广路径时,某个节点是否被添加了
    //因为找到了一条比原来长的增广路径以后 直接return,所以没有必要回溯
    vector<bool> memo(maxNode,false);
    //边的集合,记录每个节点指向的边
    vector<vector<Edge>> edges; 

    for(int j = 0 ;j<V.size();j++)
    {
        if(metched[j] == -1 )
        {
            memo=vector(maxNode,false);
            if(dfs_(j))
            {   
                counts++;
            }

        }
    }
    return counts;
}


bool dfs_(int u)
{
    //遍历该节点指向的边,去寻找一条更长的增广路径
    for(int i=0;i<edges[u].size();i++)
    {
        //在寻找增广路径时,一个节点没有被添加在该增广路径中是继续
        if(memo[edges[u][i].to] == false)
        {
            //添加到路径中
            memo[edges[u][i].to] == true;
            
            //matched(edges[u][i].to) == -1 表示找到了一条更长的路径。
            //或者是找到了一条新的路径。可能是全新,也可能是分叉
            //dfs_(matched(edges[u][i].to)) 如果该节点已经在一条增广路径中了,
            //那么递归的去寻找一条更长的
            if(matched(edges[u][i].to) == -1 
                || dfs_(matched(edges[u][i].to)))
            {
                //这两句,纯粹的表示这两个点已经在一条增广路径中了
                matched(v)=u;
                matched(u)=v;
                return true;
            }
        }
    }
    return false;
}

dfs_中,通过遍历点,不断的去增长增广路径,每次增加1(只是说在之前找到的基础上增加了,但是该路径的开头却没有了。),或者是寻找新的分叉和新的路径(通常是一对点,一一匹配)。
每次如果增广路径增加的时候,dfs_的参数,和最终找到的matched(edges[u][i].to) == -1,被增加到路径中,所以每次都增加两个节点。
这样可以确保counts++
其中保存的metched中存放的就是匹配好的对。

类似流程为:

  1. 第一轮:A->B
  2. 第二轮:C->B
    递归dfs_(B)给B匹配好的A从新寻找一个新的对象,让C能够匹配B,3而A去匹配新找到的。
    C->B->A->D
    如果递归没找到,那么C重新从新再去匹配一个,不在匹配B
    C->E
  3. 第三轮F->B
    同第二轮。
    如果F只指向B,那么F将不能匹配到对象

关键字在一个“腾”,让已匹配的再去匹配别的,腾出一个给我。

KM算法

带权重的完备匹配。寻找最大权重的匹配
完备匹配下的最大权匹配

这种算法只有描述,没有原理,算法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容