hdu 1669(二分圖多重匹配+二分列舉)
阿新 • • 發佈:2019-02-13
題意:在通訊錄中有N個人,每個人能可能屬於多個group,現要將這些人分組m組,設各組中的最大人數為max,求出該最小的最大值
解題思路:解決這道題之前,首先要搞清楚二分圖的多重匹配問題。
在二分圖最大匹配中,每個點最多隻能夠和一條匹配邊相關聯,然而我們經常會遇到這樣的問題,即二分圖匹配中一個點可以和多條匹配邊相關聯,但有上限,或者說,n表示點i最多可以和多少個匹配邊相關聯。
解決方法:改進匈牙利演算法
1、從G={X,Y;E}中取一個初始匹配值M,設定上限下限。
2、對最大限制n進行二分匹配。
3、若x都被M匹配,則可行,轉至2。否則若與yi的匹配數量小於n,則匹配xi,yi
4、如果yi匹配達到上限,那麼在yi中選擇一個元素增廣,如果能夠讓出位置,匹配xi,yi,轉至2
這裡完全就是一個模板了,先用二分列舉最大人數,然後用在用匈牙利演算法判斷是否滿足即可。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 1005; int n,m,max_cap,g[maxn][maxn]; int link[maxn][maxn],num[maxn]; bool vis[maxn]; char str[maxn]; bool dfs(int u) { for(int i = 0; i < m; i++) { if(g[u][i] > 0 && vis[i] == false) { vis[i] = true; if(num[i] < max_cap) { link[i][num[i]++] = u; return true; } for(int j = 0; j < num[i]; j++) { if(dfs(link[i][j])) { link[i][j] = u; return true; } } } } return false; } bool Max_Match(int limit) { max_cap = limit; memset(link,0,sizeof(link)); memset(num,0,sizeof(num)); for(int i = 0; i < n; i++) { memset(vis,false,sizeof(vis)); if(!dfs(i)) return false; } return true; } int getDigit(int s,int e) { int ans = 0; for(int i = s; i <= e; i++) ans = ans * 10 + str[i] - '0'; return ans; } int main() { while(cin >> n >> m,n+m) { memset(g,0,sizeof(g)); for(int i = 0; i < n; i++) { cin >> str; gets(str); int len = strlen(str); for(int j = 1,k; j < len; j = k + 1) { k = j; while(str[k] != ' ' && str[k] != '\0') k++; g[i][getDigit(j,k-1)] = 1; } } int l = 1,r = n,mid,ans; while(l <= r) { mid = (l + r) >> 1; if(Max_Match(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } printf("%d\n",ans); } return 0; }