图的最大匹配算法

Posted Only the Strong Survive

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图的最大匹配算法相关的知识,希望对你有一定的参考价值。

定义:在一个无向图中,定义一条边覆盖的点为这条边的两个端点。找到一个边集S包含最多的边,使得这个边集覆盖到的所有顶点中的每个顶点只被一条边覆盖。S的大小叫做图的最大匹配。

二分图的最大匹配算法:设左边集合为A集合,有边集合为B集合。二分图最大匹配常用的有两种方法。

(1)第一种方法叫做匈牙利算法。这个方法依次枚举A中的每个点,试图在B集合中找到一个匹配。对于A集合中一点x,假设B集合中有一个与其相连的点y,若y暂时还没有匹配点,那么x可以和y匹配,找到;否则,设y已经匹配的点为z(显然z是A集合中的一个点),那么,我们将尝试为z找到一个除了y之外的匹配点,若找到,那么x可以和y匹配,否则x不能与y匹配。

我们以下图为例说明匈牙利匹配算法。

step1:从1开始,找到右侧的点4,发现点4没有被匹配,所以找到了1的匹配点为4 。得到如下图:

step2:接下来,从2开始,试图在右边找到一个它的匹配点。我们枚举5,发现5还没有被匹配,于是找到了2的匹配点,为5.得到如下图:

step3:接下来,我们找3的匹配点。我们枚举了5,发现5已经有了匹配点2。此时,我们试图找到2除了5以外的另一个匹配点,我们发现,我们可以找到7,于是2可以匹配7,所以5可以匹配给3,得到如下图:

此时,结束,我们得到最大匹配为3。

(2)第二种方法叫做Hopcroft-Karp算法。这个算法大致思想与第一个方法相同。不同之处在于,这个方法每次找到一组互不相交的增广路径。我们用下面的例子说明。

step1:我们从所有未找到增广路径的点,也就是1,2,3,4开始,找增广路径,我们找到了1->2,3->3两条(左边的红线表示增广路径),然后沿着这些增广路径求匹配点,得到了右边的图,即1匹配2,3匹配3。

一般图的最大匹配算法:我们从一个没有匹配的节点s开始,使用BFS生成搜索树。每当发现一个节点u,如果u还没有被匹配,那么就可以进行一次成功的增广,即s匹配u;否则,我们就把节点u和它的配偶v一同接到树上,之后把v丢进队列继续搜索。我们给每个在搜索树上的点一个类型:S或者T。当u把它的配偶v扔进队列的时候,我们把u标记为T型,v标记为S型。于是,搜索树的样子是这样的:

否则,我们找到了一个长度为奇数的环,如下图所示

 就要进行一次“缩花”的操作!所谓缩花操作,就是把这个环缩成一个点。这个图缩花之后变成了5个点(一个大点,或者叫一朵花,加原来的4个点):缩点完成之后,还要把原来环里面的T型点统统变成S型点,如下图

之所以能缩成一个点,是因为,一个长度为奇数的环(例如上图中的s-b-d-j-f-c-a-s),如果我们能够给它中的任意一个点找一个出度,那么环中的其他点正好可以配成对,这说明,每个点的出度都是等效的。这就是缩点的思想来源。
 
 

 
无向图最大匹配实现:

  1 #define MAXN 250
  2 
  3 class GraphMaxMatch
  4 {
  5 private:
  6     int que[MAXN],queHead,queTail;
  7     bool g[MAXN][MAXN];
  8     bool inque[MAXN],inblossom[MAXN];
  9     int match[MAXN],pre[MAXN],S[MAXN];
 10     int n;
 11 
 12     void addQueEle(int u)
 13     {
 14         if(inque[u]) return;
 15         inque[u]=1;
 16         que[queTail++]=u;
 17         if(queTail==MAXN) queTail=0;
 18     }
 19     int popQueEle()
 20     {
 21         int u=que[queHead++];
 22         if(queHead==MAXN) queHead=0;
 23         return u;
 24     }
 25 
 26     int findancestor(int u,int v)
 27     {
 28         int visit[MAXN];
 29         memset(visit,0,sizeof(visit));
 30         while(1)
 31         {
 32             u=S[u];
 33             visit[u]=1;
 34             if(match[u]==-1) break;
 35             u=pre[match[u]];
 36         }
 37         while(1)
 38         {
 39             v=S[v];
 40             if(visit[v]) break;
 41             v=pre[match[v]];
 42         }
 43         return v;
 44     }
 45     void reset(int u,int root)
 46     {
 47         int v;
 48         while(u!=root)
 49         {
 50             v=match[u];
 51             inblossom[S[u]]=1;
 52             inblossom[S[v]]=1;
 53             v=pre[v];
 54             if(S[v]!=root) pre[v]=match[u];
 55             u=v;
 56         }
 57     }
 58 
 59     void contract(int u,int v)
 60     {
 61         int root=findancestor(u,v);
 62         memset(inblossom,0,sizeof(inblossom));
 63         reset(u,root); reset(v,root);
 64         if(S[u]!=root) pre[u]=v;
 65         if(S[v]!=root) pre[v]=u;
 66         for(int i=1;i<=n;i++) if(inblossom[S[i]])
 67         {
 68             S[i]=root;
 69             addQueEle(i);
 70         }
 71     }
 72 
 73     bool BFS(int start)
 74     {
 75         for(int i=1;i<=n;i++) pre[i]=-1,inque[i]=0,S[i]=i;
 76         queHead=queTail=0;
 77         addQueEle(start);
 78         while(queHead!=queTail)
 79         {
 80             int u=popQueEle();
 81 
 82             for(int v=1;v<=n;v++) if(g[u][v]&&S[v]!=S[u]&&match[u]!=v)
 83             {
 84                 if(v==start||match[v]!=-1&&pre[match[v]]!=-1)
 85                 {
 86                     contract(u,v);
 87                 }
 88                 else if(pre[v]==-1)
 89                 {
 90                     pre[v]=u;
 91                     if(match[v]!=-1) addQueEle(match[v]);
 92                     else
 93                     {
 94                         u=v;
 95                         while(u!=-1)
 96                         {
 97                             v=pre[u];
 98                             int tmp=match[v];
 99                             match[u]=v;
100                             match[v]=u;
101                             u=tmp;
102                         }
103                         return true;
104                     }
105                 }
106             }
107         }
108         return false;
109     }
110 public:
111     /**
112     vertexNum: vertex number
113     G[1~vertexNum][1~vertexNum]: edge relation
114     */
115     vector<pair<int,int> > calMaxMatch(
116                 int vertexNum,const bool G[MAXN][MAXN])
117     {
118         n=vertexNum;
119         for(int i=1;i<=n;i++)
120         {
121             for(int j=1;j<=n;j++) g[i][j]=G[i][j];
122         }
123         memset(match,-1,sizeof(match));
124         for(int i=1;i<=n;i++) if(match[i]==-1) BFS(i);
125 
126         vector<pair<int,int> > ans;
127         for(int i=1;i<=n;i++)
128         {
129             if(match[i]!=-1&&match[i]>i)
130             {
131                 ans.push_back(make_pair(i,match[i]));
132             }
133         }
134         return ans;
135     }
136 };

 

以上是关于图的最大匹配算法的主要内容,如果未能解决你的问题,请参考以下文章

(转)二分图的最大匹配完美匹配和匈牙利算法

图的最大匹配算法

二分图的最大匹配完美匹配和匈牙利算法

(转)二分图的最大匹配完美匹配和匈牙利算法

二分图的最大匹配完美匹配和匈牙利算法

二分图的最大匹配完美匹配和匈牙利算法