漫谈匈牙利算法

匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名。匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。(来自百度百科)

浅显的讲,就是寻找二部图的最大匹配,先写出几个概念;

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

6B974A22-EFFB-4813-BF81-6149A037675A.png

当子图中没有任何一个同时连接Xi和Yj的同一顶点的时候我们称为二部图的一个匹配,记为集合M

什么是最大匹配呢 如下图

9C2492EA-5019-4BC5-A84D-A2856E55E603.png

当匹配集合中的边数达到最大的时候,这就是一个最大匹配,如上图;

再提出几个个概念
未覆盖点:就是在集合M中没有边连接到的点称为未覆盖点。
完美匹配:当M是二部图的最大匹配且没有未覆盖点的时候,则这个集合M就是二部图的完美匹配。上图中的匹配就是完美匹配,在符合最大匹配的同时,M集合中的边覆盖了二部图的所有点。

最后一个最关键的概念:增广路径 ;
匈牙利算法的核心就是不停的寻找增广路径来扩充匹配集合M,什么是增广路经呢?(来自百度百科)

1-P的路径长度必定为奇数。
2-起点在左,终点在右。
3-路径中的点左右交替出现。
4-只有起点和终点是未覆盖点,其他点都配对。
5 -对增广路径编号,所有奇数的边都不在M中,偶数边在M中。
6 -对增广路径取反得到的匹配比原来匹配多一个。

我们给出实例来理解。


C33D49B0-2527-48FF-A442-762BEB630E01.png

我们寻找如上图的最大匹配;首先M集合为空(即没有边在里面),然后开始从X1寻找增广路,遵循2的原则我们只能在Yi中找,找到Y1,(X1,Y1 )这条路径,满足1-5的条件,取反,将(X1,Y1 )这条路径加入到M中。

2E79CD71-536E-4171-9156-844F956A8EF5.png

接着,我们找到X2点,遵循原则,找到Y1,Y1不是未覆盖点,这个时候我们有两种选择,一个是深度搜索,一个是广度搜索,我们采用深度优先,虽然Y1不是未覆盖点,(X2,Y1)不是增广路,但是Y1连着X1,X1又和Y3相连,我们考虑( X2,Y1,X1,Y3 )这条路径,奇数?左右交替?起终点未覆盖?奇路径不属于M偶路径属于?满足所有增广路条件,所以这是一条增广路径,然后取反,得到如下图。

5213FA71-C31A-4461-9A5F-54AF59BF4B02.png

现在M集合中的路径有两条了,由于我们找到了增广路径,使得M中的边数量增加。所以增广路径是匈牙利算法的核心,每找到一条增广路径,意味这M集合中边的数量就会增加1,当找不到增广路径的时候,这个时候M中边的数量就是我们二部图的最大匹配数量。我们是怎样找到这条路径的呢,从X2开始寻找,我们先找到Y1,Y1不是未覆盖点,我们考虑Y1的原有匹配点X1,从X1开始寻找增广路,找到了Y3,当X1有增广路的时候,那么加上(X1,Y1)(X2,Y1)这两条路经,依然满足增广路条件。所以基于我们上面的理解可以给出寻找增广路的伪代码

  while(找到Xi的关联顶点Yj){
          if(顶点Yj不在增广路径上){
                将Yj加入增广路
               if(Yj是未覆盖点或者Yj的原匹配点Xk能找到增广路径){ //扩充集合M
                      将Yj的匹配点改为Xi;
                      返回true
           }
      }
               返回false
}

从X2开始寻找是基于深度优先的,如果是基于广度优先呢?那么X2就会找到Y2。

给出C语言代码


typedef struct tagMaxMatch{
    int edge[COUNT][COUNT];
    bool on_path[COUNT];
    int path[COUNT];
    int max_match;
}GRAPH_MATCH;

void outputRes(int *path){
    for (int i = 0 ; i<COUNT; i++) {
        printf("%d****%d\n",i,*(path+i));   //Yj在前 Xi在后
    }
}

void clearOnPathSign(GRAPH_MATCH *match){
    for (int j = 0 ; j < COUNT ; j++) {
        match->on_path[j] = false;
    }
   
}
//dfs算法
bool FindAugPath(GRAPH_MATCH *match , int xi){
    
    for (int yj = 0 ; yj < COUNT; yj++) {
        if ( match->edge[xi][yj] == 1 && !match->on_path[yj]) { //如果yi和xi相连且yi没有在已经存在的增广路经上
             match->on_path[yj] = true;
            if (match->path[yj] == -1 || FindAugPath(match,match->path[yj])) { // 如果是yi是一个未覆盖点或者和yi相连的xk点能找到增广路经,
                  match->path[yj] = xi; //yj点加入路径;
                  return true;
            }
        }
    }
    return false;
}

void Hungary_match(GRAPH_MATCH *match){
    for (int xi = 0; xi<COUNT ; xi++) {
          FindAugPath(match, xi);
          clearOnPathSign(match);
    }
    outputRes(match->path);
}

int main() {
    
    GRAPH_MATCH *graph = (GRAPH_MATCH *)malloc(sizeof(GRAPH_MATCH));
    for (int i = 0 ; i < COUNT ; i++) {
        for (int j = 0 ; j < COUNT ; j++) {
            graph->edge[i][j] = 0;
        }
    }
    graph->edge[0][1] = 1;
    graph->edge[0][0] = 1;
    graph->edge[1][1] = 1;
    graph->edge[1][2] = 1;
    graph->edge[2][1] = 1;
    graph->edge[2][0] = 1;
    graph->edge[3][2] = 1;
    
    for (int j = 0 ; j < COUNT ; j++) {
        graph->path[j] = -1;
        graph->on_path[j] = false;
    }
    
    Hungary_match(graph);
    
    
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容

  • (转自http://www.douban.com/group/topic/14820131/,转自人大论坛) 调整...
    f382b3d9bdb3阅读 10,195评论 0 8
  • 来源: http://www.douban.com/group/topic/14820131/ 调整变量格式: f...
    MC1229阅读 6,903评论 0 5
  • 题目内容 链接: POJ3041 算法详解 二分图相关知识 wiki百科已经写得挺详细了,主要讲一下二分图求最大匹...
    玩毛线的毛线阅读 1,039评论 0 0
  • 转载请声明 原文链接 关注公众号获取更多资讯 这篇文章主要总结H5的一些新增的功能以及一些基础归纳,这里只是一个提...
    程序员poetry阅读 9,056评论 22 225
  • 1、前言 学习是一个痛苦的过程,让我们养成了不求甚解的习惯。 2、匈牙利算法 嗯,首先网上已经有很多啦。但是我觉得...
    bplusb阅读 856评论 2 2