POJ - 2289 Jamie's Contact Groups (二分图多重匹配)
题意:N个人,M个团体。每个人有属于自己的一些团体编号。将每个人分配到自己属于的团体中,问这个人数最多的团体其人数最小值是多少。
分析:一个一对多的二分图匹配,且是最大值最小化问题。二分图的多重匹配建立在匈牙利算法的基础上,令每个Y部的点可匹配多个点,但是规定其上限,超过上限就要在已有的匹配点中寻找增广路。对于X部的点,只要有一个点没有被匹配,那么算法失败。以此二分确定答案,注意二分的姿势...
该题可做模板。
#include<iostream> #include<stdio.h> #include<cmath> #include<cstring> #include<algorithm> #include<vector> using namespace std; typedef long long LL; const int maxn = 1e3+5,maxm = 5e5+5; int N,M; struct Node{ int K[maxn]; }link[maxn]; int cnt[maxn]; struct Edge{ int to,next; }edges[maxm]; int head[maxn],tot; int linker[maxn]; bool used[maxn]; void init() { tot=0; memset(head,-1,sizeof(head)); } void AddEdge(int u,int v) { edges[tot].to = v; edges[tot].next = head[u]; head[u] = tot++; } bool dfs(int u,int limit){ int v; for(int i=head[u];~i;i = edges[i].next){ v = edges[i].to; if(!used[v]){ used[v]=true; if(cnt[v]<limit){ link[v].K[cnt[v]++]=u; return true; } for(int j=0;j<cnt[v];++j){ if(dfs(link[v].K[j],limit)){ link[v].K[j]=u; return true; } } } } return false; } bool hungary(int limit){ memset(cnt,0,sizeof(cnt)); for(int u=1;u<=N;u++){ memset(used,0,sizeof(used)); if(!dfs(u,limit)) return false; //只要有一个人不能匹配则失败 } return true; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int T,u,v,tmp,k; char c; while(scanf("%d%d",&N,&M)==2){ if(!N) break; init(); for(int u=1;u<=N;++u){ char op[maxn]; scanf("%s",op); while(true){ scanf("%d%c",&v,&c); AddEdge(u,v+1); if(c == '\n') break; } } int L=1,R=N,mid,ans=N; while(L<=R){ mid = (L+R)>>1; if(hungary(mid)){ ans = mid; R = mid-1; } else L=mid+1; } printf("%d\n",ans); } return 0; }
为了更好的明天