n个人分成m组,求人数最多的那一组人数的最小值。
每个人肯定只能匹配一个组,但一个组可以匹配多个人,因此属于多重匹配。
我们设置一个limit,表示每组最多能容纳的人数。在dfs(u)寻找u的匹配时,如果某一组vv的人数小于limit,那么可以把u和vv匹配,vv已经匹配的人数+1。否则,当人数已经达到limit,我们对vv的每个匹配做dfs,即寻找增广,若能找到,修改这个匹配,即让vv和u匹配。
然后我们可以二分limit,当u集合(人的集合)中所有点都能找到匹配,则减小limit值,否则只要有一个点找不到匹配,增大limit值。
多重匹配和二分匹配匈牙利算法的写法类似,只不过加了一个cnt数组表示v已经匹配到的人数,linker数组也增加了一维。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 using namespace std; 5 int n,m; 6 vector<int> v[1100]; 7 int linker[1100][1100],vis[1100],cnt[1100]; 8 int limit; 9 bool dfs(int u) 10 { 11 int i,j; 12 for(i=0;i<v[u].size();i++) 13 { 14 int vv=v[u][i]; 15 if(!vis[vv]) 16 { 17 vis[vv]=1; 18 if(cnt[vv]<limit) 19 { 20 linker[vv][cnt[vv]++]=u; 21 return true; 22 } 23 else 24 { 25 for(j=0;j<cnt[vv];j++) 26 { 27 if(dfs(linker[vv][j])) 28 { 29 linker[vv][j]=u; 30 return true; 31 } 32 } 33 } 34 } 35 } 36 return false; 37 } 38 int main() 39 { 40 int i,j; 41 char str[110000]; 42 while(scanf("%d%d",&n,&m)!=EOF) 43 { 44 getchar(); 45 if(n==0&&m==0) break; 46 for(i=0;i<n;i++) 47 v[i].clear(); 48 for(i=0;i<n;i++) 49 { 50 gets(str); 51 int len=strlen(str); 52 j=0; 53 loop:for(;j<len;j++) 54 { 55 if(str[j]>='0'&&str[j]<='9') 56 break; 57 } 58 int num=0; 59 bool judge=false; 60 for(;j<len;j++) 61 { 62 if(str[j]>='0'&&str[j]<='9') 63 { 64 judge=true; 65 num=num*10+(str[j]-'0'); 66 } 67 else break; 68 } 69 if(judge) v[i].push_back(num); 70 if(j<len) goto loop; 71 } 72 int l=0,r=n; 73 while(l<r) 74 { 75 limit=(l+r)/2; 76 memset(cnt,0,sizeof(cnt)); 77 for(i=0;i<n;i++) 78 { 79 memset(vis,0,sizeof(vis)); 80 if(!dfs(i)) break; 81 } 82 if(i>=n) r=limit; 83 else l=limit+1; 84 } 85 printf("%d\n",l); 86 } 87 return 0; 88 }