<题目链接>
题目大意:
有n个人,每个人都有一个或者几个能够归属的分类,将这些人分类到他们能够归属的分类中后,使所含人数最多的分类值最小,求出该分类的所含人数值。
解题分析:
看到求最大最小的问题,我们首先会想到二分答案,二分枚举所含人数最大的分块中所含人的数量,然后,根据枚举出的数量,进行二分图的多重匹配,如果当前分块所含人数<枚举的上限,那么就暂时将该人分配当前分块,如果当前分块已满,那么就枚举当前分块中的所有人,看是否能够将其分配到其它分块,如果可以,那么就将正在匹配的人分配到那个能够分配到其它分块的人的位置上,最后,判断是否所有人都能够分配到分块中,即二分答案的check。
1 #include <cstdio> 2 #include <cstring> 3 #include <string> 4 #include <vector> 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 9 const int N = 1e3+10; 10 int n,m; 11 int vis[N],match[N][N],num[N]; 12 vector<int>vec[N]; 13 string s; 14 bool dfs(int u,int mx){ 15 for(int i=0;i<vec[u].size();i++){ 16 int v=vec[u][i]; 17 if(!vis[v]){ 18 vis[v]=1; 19 if(num[v]<mx){ //如果该分块中人数小于当前缩枚举的容量,则将该人(暂时)分配到该分块 20 match[v][++num[v]]=u; 21 return true; 22 } 23 for(int k=1;k<=num[v];k++){ 24 if(dfs(match[v][k],mx)){ //如果该分块中的人数已满,就枚举这个分块之前分配的所有人,看其是否能够分配到其它分块 25 match[v][k]=u; //如果该分块的第k个人能够分配到其它分块,那么u就能够分配到当前分块 26 return true; 27 } 28 } 29 } 30 } 31 return false; 32 } 33 int Hungary(int mx){ 34 int ans=0; 35 memset(num,0,sizeof(num)); 36 for(int i=1;i<=n;i++){ 37 memset(vis,0,sizeof(vis)); 38 ans+=dfs(i,mx); 39 } 40 return ans; 41 } 42 int main(){ 43 while(scanf("%d%d",&n,&m)!=EOF,n||m){ 44 for(int i=0;i<=n;i++)vec[i].clear(); 45 for(int i=1;i<=n;i++){ 46 int data; 47 cin>>s; 48 while(true){ 49 scanf("%d",&data); 50 vec[i].push_back(data+1); 51 if(getchar()==' ')break; 52 } 53 } 54 int l=1,r=n,ans=0; 55 while(l<=r){ //二分答案,枚举所含人数最多的分块中人的数量 56 int mid=(l+r)>>1; 57 if(Hungary(mid)==n)ans=mid,r=mid-1; //如果所有人都能够分配到分块中(即,当前二分的答案满足题意),那么就继续缩小 枚举的分块中的最多人数数量 58 else l=mid+1; 59 } 60 printf("%d ",ans); 61 } 62 }
2018-11-17