二分图多重匹配+二分
对于每个组设置匹配上限,然后用二分图多重匹配看能否全部匹配好
直到找到最小的上限,这就是最大的组的最小值,这个过程可以用二分来优化
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<sstream>
using namespace std;
typedef long long ll;
const int N=1000+10;
const int M=500+10;
const int INF=0x7f7f7f7f;
int uN,vN;
int g[N][M];
int linker[N][M];
bool used[M];
int num[M];
bool dfs(int u)
{
for(int v=0;v<vN;v++)
if(g[u][v]&&!used[v])
{
used[v]=true;
if(linker[v][0]<num[v])
{
linker[v][++linker[v][0]]=u;
return true;
}
for(int i=1;i<=num[0];i++)
if(dfs(linker[v][i]))
{
linker[v][i]=u;
return true;
}
}
return false;
}
int hungary()
{
int res=0;
for(int i=0;i<vN;i++)
linker[i][0]=0;
for(int u=0;u<uN;u++)
{
memset(used,false,sizeof(used));
if(dfs(u)) res++;
}
return res;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
getchar();
memset(g,0,sizeof(g));
for(int i=0;i<n;i++)
{
string s;
stringstream ss;
getline(cin,s);
ss<<s;
ss>>s;
int a;
while(ss>>a)
g[i][a]=1;
}
uN=n;vN=m;
int ans=n,l=1,r=n;
while(l<r)
{
int m=(l+r)>>1;
for(int v=0;v<vN;v++)
num[v]=m;
int num=hungary();
if(num<n)
{
l=m+1;
}
else
{
r=m;
ans=m;
}
}
int m=(l+r)>>1;
memset(num,m,sizeof(num));
int num=hungary();
if(num==n) ans=m;
printf("%d\n",ans);
}
return 0;
}