圖的最大匹配算法


定義:在一個無向圖中,定義一條邊覆蓋的點為這條邊的兩個端點。找到一個邊集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 };

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM