二分最少每个分组能有多少人,然后用匈牙利算法去匹配,如果这个分组的人少于给定的最少人数,则匹配,如果大于,去找增广路,更换匹配对象。
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#define LL long long
#define mem(a, b) memset(a, b, sizeof(a))
#define N 1005
#define MOD
using namespace std;
int n, m, vis[N], x, mp[N][N];
char ch, s[20];
struct node{
int cnt;
int match[N];
}se[N];
bool dfs(int x, int y) {
for(int i=1; i<=m; i++) {
if(!vis[i] && mp[x][i]) {
vis[i]=1;
if(se[i].cnt<y) {
se[i].match[se[i].cnt++]=x;
return 1;
}
for(int j=0; j<se[i].cnt; j++) {
if(dfs(se[i].match[j], y)) {
se[i].match[j]=x;
return 1;
}
}
}
}
return 0;
}
bool judge(int x) {
mem(se, 0);
for(int i=1; i<=n; i++) {
mem(vis, 0);
if(!dfs(i, x)) return 0;
}
return 1;
}
int main() {
int cnt=0;
while(scanf("%d%d", &n, &m)!=EOF && n && m) {
mem(mp, 0);
for(int i=1; i<=n; i++) {
scanf("%s", s);
while(1) {
scanf("%d%c", &x, &ch);
mp[i][x+1]=1;
if(ch=='\n') break;
}
}
int l=1, r=n;
while(l<r) {
int mid=(l+r)>>1;
if(judge(mid)) r=mid;
else l=mid+1;
}
cout<<l<<endl;
}
}