题意:
给定一个规模为n的名单,要将名单中的人归到m个组中,给出每个人可能的分组号,需要确定一种分配方案,使得最大规模的组最小。
思路:
二分图多重匹配
如果所到的组没满,就去那个组
如果满了,就从那个组里踢出一个
如果能踢出来,就把那个踢出来,把当前的放进去
如果所有能到的组都踢不出来,就不对了
至于那个最大规模的具体值,二分一下就OK了
/* *********************************************** Author :devil Created Time :2016/5/17 17:56:52 ************************************************ */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <stdlib.h> using namespace std; const int N=1010; const int M=510; int n,m,mid,x; char s[20]; bool vis[M]; vector<int>eg[N],isin[M]; bool Find(int u) { for(int i=0;i<eg[u].size();i++) { int v=eg[u][i]; if(!vis[v]) { vis[v]=1; if(isin[v].size()<mid) { isin[v].push_back(u); return 1; } for(int j=0;j<isin[v].size();j++) { if(Find(isin[v][j])) { isin[v][j]=u; return 1; } } } } return 0; } bool maxmatch() { for(int i=0;i<m;i++) isin[i].clear(); for(int i=0;i<n;i++) { memset(vis,0,sizeof(vis)); if(!Find(i)) return 0; } return 1; } int main() { //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)&&(n+m)) { for(int i=0;i<n;i++) eg[i].clear(); for(int i=0;i<n;i++) { scanf("%s",s); while(scanf("%d",&x)==1) { eg[i].push_back(x); if(getchar()==' ') break; } } int l=0,r=n; while(l<r) { mid=(l+r)>>1; if(maxmatch()) r=mid; else l=mid+1; } printf("%d ",r); } return 0; }