匈牙利算法

来源:互联网 发布:淘宝哪家茶叶店靠谱 编辑:程序博客网 时间:2024/06/06 16:53

https://www.byvoid.com/blog/hungary

http://comzyh.com/blog/archives/148/

匈牙利算法是解决二分图匹配的问题。

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

给定一个二分图G,M为G边集的一个子集,如果M满足当中的任意两条边都不依附于同一个顶点,则称M是一个匹配。

极大匹配(Maximal Matching)是指在当前已完成的匹配下,无法再通过增加未完成匹配的边的方式来增加匹配的边数。最大匹配(maximum matching)是所有极大匹配当中边数最大的一个匹配。选择这样的边数最大的子集称为图的最大匹配问题。(见下图)

如图蓝线所示是一种最大二分匹配方案,匹配数=3

二分图

最大二分匹配


匈牙利算法过程


模拟步骤如右图所示(过于详细,大牛请无视):

  1. 初始化(清空)
  2. 从A所连接的点中找到一个未在本次循环中搜索过的点2,并将2标记为搜索过,因为2没有被连接过,匹配A2
  3. 结束上次,开始新的循环,将所有点标记为未搜索过
  4. 搜索B,找到一个未在本次循环中搜索过的点2,标记为搜索过
  5. 发现2被匹配过,从2的父亲A寻找增广路,递归搜索A{从A所连接的点中找到一个未在本次循环中搜索过的点5(1已经标记为绿色),将5标记为搜索过,因为5没有被匹配过,匹配A5}找到增广路(此处为增广路的关键
  6. 结束上次,开始新的循环,将所有点标记为未搜索过
  7. 搜索C,找到一个未在本次循环中搜索过的点1,并将1标记为搜索过,发现1未被匹配过,匹配C1
  8. 结束上次,开始新的循环,将所有点标记为未搜索过
  9. 搜索D,找到一个未在本次循环中搜索过的点1,并将1标记为搜索过,发现1被匹配过,递归搜索1的源C寻找增广路
  10. {搜索C,找到一个未在本次循环中搜索过的点5,标记为搜索过,发现5被匹配,进一步返现没有其他可连接点,返回找不到增广路}返回第9步
  11. 搜索D,找到一个未在本次循环中搜索过的点2,发现2被匹配,递归搜索2的源B寻找增广路
  12. {搜索B,找到一个未在本次循环中搜索过的点3,并将3标记为搜索过,发现3未被匹配,匹配B3返回找到}既然B另寻新欢,匹配D2
  13. 结束上次,开始新的循环,将所有点标记为未搜索过,递归搜索D寻找增广路
  14. 搜索E,找到一个未在本次循环中搜索过的点2,并将2标记为搜索过,发现2被匹配过,递归搜索2的源D寻找增广路
  15. {搜索D,发现1,5均被匹配过,返回找不到增广路}
  16. E无其他可连接节点,放弃E,E后无后续节点,已经遍历A-E,结束算法


  1. #include <iostream>#include <fstream>#include <stdlib.h>#include <memory.h>using namespace std;int tab[201][201];//邻接矩阵,不是真正意义的邻接矩阵,第一维对应牛,第二维对应牛棚int state[201],result[201];//stata:是否被搜索过;result:某牛栏对应的牛int n,m;int ans;//找到多少匹配int find(int x){// 匈牙利算法    int i;    for (i=1;i<=m;i++){        if (tab[x][i]==1 && !state[i]){           state[i]=1;//标记为搜索过           if (result[i]==0//未被匹配过   || find(result[i])){//能找到一条增广路              result[i]=x;//匹配i,x              return 1;//能找到新的匹配              }           }        }    return 0;    }int main(){    int i,j;    int n1,t;    cin >> n >> m;    memset(tab,0,sizeof(tab));    for (i=1;i<=n;i++){        cin >> n1;        for (j=1;j<=n1;j++){            cin >> t;            tab[i][t]=1;            }        }    for (i=1;i<=n;i++){        memset(state,0,sizeof(state));//清空是否搜索过数组        if (find(i)) ans++;//找到新的匹配        }//完成后 Result[i]保存着第i个牛栏对应的奶牛,本题不用输出,其他题有可能用    cout << ans<< endl;    //system("pause");    return 0;    }


0 0