图匹配
二分圖:
二分圖又稱作二部圖,是圖論中的一種特殊模型。 設G=(V,E)是一個無向圖,如果頂點V可分割為兩個互不相交的子集(A,B),并且圖中的每條邊(i,j)所關聯的兩個頂點i和j分別屬于這兩個不同的頂點集(i in A,j in B),則稱圖G為一個二分圖。
簡單的說,一個圖被分成了兩部分,相同的部分沒有邊,那這個圖就是二分圖,二分圖是特殊的圖。
匹配:
給定一個二分圖G,在G的一個子圖M中,M的邊集{E}中的任意兩條邊都不依附于同一個頂點,則稱M是一個匹配。
極大匹配(Maximal Matching)是指在當前已完成的匹配下,無法再通過增加未完成匹配的邊的方式來增加匹配的邊數。
最大匹配(maximum matching)是所有極大匹配當中邊數最大的一個匹配。選擇這樣的邊數最大的子集稱為圖的最大匹配問題。
如果一個匹配中,圖中的每個頂點都和圖中某條邊相關聯,則稱此匹配為完全匹配,也稱作完備匹配。
求二分圖匹配可以用最大流(Maximal Flow)或者匈牙利算法(Hungarian Algorithm)
注意匈牙利算法,除了二分圖多重匹配外在二分圖匹配中都可以使用。
注:二分圖匹配中還有一個hk算法,復雜度為o(sqrt(n)*e)由于復雜度降低較低,代碼量飆升而且絕大多數情況下沒人會閑的卡個sqrt的復雜度。。在此先不講了,有興趣可以自己百度,貌似卡這個算法的只有hdu2389
匈牙利算法:
匈牙利算法幾乎是二分圖匹配的核心算法,除了二分圖多重匹配外均可使用
匈牙利算法實際上就是一種網絡流的思想,其核心就是尋找增廣路。具體操作就是嗯。。拉郎配
?
注:以下轉自?http://blog.csdn.net/dark_scope/article/details/8880547
匈牙利算法是由匈牙利數學家Edmonds于1965年提出,因而得名。匈牙利算法是基于Hall定理中充分性證明的思想,它是部圖匹配最常見的算法,該算法的核心就是尋找增廣路徑,它是一種用增廣路徑求二分圖最大匹配的算法。
-------等等,看得頭大?那么請看下面的版本:
?
通過數代人的努力,你終于趕上了剩男剩女的大潮,假設你是一位光榮的新世紀媒人,在你的手上有N個剩男,M個剩女,每個人都可能對多名異性有好感(-_-||暫時不考慮特殊的性取向),如果一對男女互有好感,那么你就可以把這一對撮合在一起,現在讓我們無視掉所有的單相思(好憂傷的感覺),你擁有的大概就是下面這樣一張關系圖,每一條連線都表示互有好感。
?
一:?先試著給1號男生找妹子,發現第一個和他相連的1號女生還名花無主,got it,連上一條藍線
二:接著給2號男生找妹子,發現第一個和他相連的2號女生名花無主,got it
三:接下來是3號男生,很遺憾1號女生已經有主了,怎么辦呢?
我們試著給之前1號女生匹配的男生(也就是1號男生)另外分配一個妹子。
與1號男生相連的第二個女生是2號女生,但是2號女生也有主了,怎么辦呢?我們再試著給2號女生的原配()重新找個妹子(注意這個步驟和上面是一樣的,這是一個遞歸的過程)
那么第三部結果就是
?
代碼中最重要的就是遞歸了
ac代碼
#include <cstdio> #include<iostream> #include <cstring> #include <algorithm> #include <cmath> #include <cstdlib> using namespace std;typedef long long ll; const int N = 505; struct po {int id,high;char sex[10],sport[100],music[100]; }p[N];// 學生 int t,n; int ret;// 最大匹配數 int g[N][N];//建雙向遍 int used[N]; //標記 正在匹配的男同學 的 可匹配的女同學 是否已匹配 int match[N]; //標記i的匹配 u //bool dfs(int u) //{ // for(int i=1;i<=vN;i++) // { // if(!used[i] && g[u][i]) // { // used[i] = true; // if(match[i] == -1 || dfs(match[i])) // { // match[i] = u; // return true; // } // } // } // return false; //} bool dfs(int u) //遞歸 匹配 {for(int i=1;i<=n;i++){if(!used[i]&&g[u][i]){used[i]=true;if(match[i]==-1||dfs(match[i]))// 如果i 未匹配,或者可以找到其他匹配的話,就讓 u與i匹配 {match[i]=u;return true;}}}return false; } bool check(int i,int j)//檢查是否可以匹配 {if(strcmp(p[i].sex,p[j].sex)==0) return false;if(abs(p[i].high - p[j].high) > 40) return false; //身高差超過40cmif (strcmp(p[i].music, p[j].music)) return false;//喜歡的音樂類型相同if (!strcmp(p[i].sport, p[j].sport)) return false;//喜歡的體育類型不同return true; } void init()//初始化 {memset(g,0,sizeof(g));memset(match,-1,sizeof(match)); } int hungary() // 記錄ret 也就是匹配數 { int ret = 0; for(int i=1;i<=n;i++) { memset(used,0,sizeof(used)); if(p[i].sex[0]=='M'&&dfs(i)) ret++; } return ret; } int main() {cin>>t;while(t--){cin>>n;init();for(int i=1;i<=n;i++){cin>>p[i].high>>p[i].sex >>p[i].music >>p[i].sport ;p[i].id=i;}for(int i=1;i<=n;i++){for(int j = 1; j <= n; j++) //將可以匹配的男女建邊if(check(i,j)) g[i][j] = g[j][i] = 1; // 建立匹配邊 }cout<<n-hungary()<<endl; } }?
本來不想摘抄的,可是他們的代碼都沒有注釋,唉
總結
- 上一篇: 用聚宽量化炒股-3常用对象
- 下一篇: 流量控制理论与Sentinel