1. 程式人生 > >匈牙利演算法(二分圖匹配)

匈牙利演算法(二分圖匹配)

好,來講簡單的東西了

匈牙利演算法

也就是二分圖匹配

Q二分圖匹配是什麼?

還是先看題比較好
公牛和母牛
【問題描述】
有n只公牛和m只母牛,然後每隻公牛都能和幾隻的母牛配對。在每隻公牛隻能配對一隻母牛的情況下,求能為牛們配對最多多少對?
【輸入】
第一行兩個整數,n (0 ≤ n ≤ 400) 和 m (0 ≤ m ≤ 500) 。
第二行到第N+1行一共N行,每行對應一隻公牛。第一個數字 (si) 是這頭公牛有匹配關係的母牛的數目 (0 ≤ si ≤ m) 。後面的si個數表示這些母牛編號。母牛編號限定在區間 (1..m) 中。
【輸出】
輸出一個整數,表示最多能配對成功多少頭牛?

A:所謂二分圖就是像這道題說的那樣
讓公牛排一列,母牛排一列
給可以匹配的公牛母牛連一條線
然後來匹配…問最多能匹配上多少公牛?

先看思路
1. 從第一隻公牛開始遍歷每一隻母牛,直到找到一隻他可以配對的母牛;
2. 如果這隻母牛沒有配對過,那麼配對成功,返回1,下一隻公牛繼續配對。
3. 如果這隻母牛已經配對過了怎麼辦?
我們稱正在配對的這隻公牛為A,這隻母牛已經配對的公牛為B。這時,讓公牛B去進行步驟1,但是要從這隻母牛開始往後問(因為前面的母牛他在配對的時候已經問過了),看看能否找到另一隻母牛也能與之配對。

這時有兩種情況:
(1).公牛B配對成功另一頭母牛,這時公牛A就可以配對原來的母牛。
(2).公牛B沒有找到另一頭母牛配對。這時標記一開始的這頭母牛為“不可詢問狀態”,以後的其他公牛都不能詢問這頭母牛。 然後公牛A就要繼續找其他母牛了。

那麼,已經配對成功過母牛的公牛會不會喪偶?

從上面的第二種情況就可以看出,我們會確保公牛B有配偶,而不會沒有配偶(是換配偶)

題目中的母牛就是我們剛剛講的公牛。產奶的地方就是母牛QAQ

提供非常標準的程式碼

#include<cstdio>
#include<cstring>
using namespace std;
int match[501];  //標記母牛的陣列,match[i]為第i只母牛的匹配物件是第幾只公牛
int n,m,ans; //n公牛數目,m母牛數目,ans為匹配對數
bool mp[401][501] ; //mp[i][j]==true表示第i只公牛和第j只母牛有匹配關係
bool chw[501]; // 也是標記母牛可否被“詢問”的陣列(“詢問”後面有解釋)。 //如果第i只母牛chw[i]==false,表示母牛i不可被詢問,否則表示母牛i可被“詢問”。 //匈牙利演算法的關鍵點:chw陣列 bool find_muniu(int x) { for(int j=1;j<=m;j++) //逐只母牛問 if (mp[x][j]==true) //第k只公牛和第i只母牛有匹配關係 if (chw[j]==true)//問母牛i能否被“詢問” { chw[j]=false; //標記母牛i已被詢問,不管匹配成功與否,以後其他公牛都沒必要再詢問母牛i if ( match[j]==0 || find_muniu(match[j])==true ) // match[i]=0 該母牛單身 或者 find(match[i])如果該母牛已匹配公牛x(x==match[i]),嘗試讓公牛x去找其他母牛匹配 { match[j]=x; return true; //這兩句表示第i只母年匹配了第k只公牛} } } return false;//執行到這一步表示匹配不成功。 } int main() { scanf("%d%d",&n,&m);//n只公牛,m只母年 memset(mp,false,sizeof(mp));//初始化匹配關係 for(int i=1;i<=n;i++)//讀入邊,構建圖 { int kk,y;scanf("%d",&kk); //混蛋,第i只公牛竟然能和kk只母牛匹配,她們是誰? for(int j=1;j<=kk;j++) { scanf("%d",&y); mp[i][y]=true; } } ans=0;//匹配對數初始化為0 memset(match,0,sizeof(match));//每隻母牛初始化為未匹配(match[i]=0) for(int i=1;i<=n;i++) //公牛逐個逐個找母牛 { memset(chw,true,sizeof(chw)); //所有母牛初始化為可“詢問” if(find_muniu(i)==true)ans++;//如果找到了,總體增加一對 //思考:匹配成功的公牛會不會被後來的公牛搶了母牛? } printf("%d\n",ans);//輸出最大匹配對數 for(int i=1;i<=m;i++)//詢問每隻母牛有沒有匹配到公牛 if(match[i]>0) //如果母牛i已經匹配,輸出匹配了哪隻公牛 printf("%d %d\n",match[i],i); return 0; }