题意:在通讯录中有N个人,每个人能可能属于多个group,现要将这些人分组m组,设各组中的最大人数为max,求出该最小的最大值
下面用的是朴素的查找,核心代码find_path复杂度是VE的,不过据说可以用DINIC跑二分图可以得到sqrt(v)*E的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long Ull;
#define MM(a,b) memset(a,b,sizeof(a));
const double eps = 1e-10;
const int inf =0x7f7f7f7f;
const double pi=acos(-1);
const int maxn=100000;
int n,m,k;
int mp[1005][505],link[505][1005],num[505],vis[505];
char s[20],c;
bool find_path(int u,int mid)
{
for(int v=0;v<m;v++)
if(mp[u][v]&&!vis[v])
{
vis[v]=1;
if(num[v]<mid)
{
link[v][++num[v]]=u;
return true;
}
for(int i=1;i<=num[v];i++)
if(find_path(link[v][i],mid))
{
link[v][i]=u;
return true;
}
//vis[v]=0;这个地方不能将vis[v]清0,否则将多次重复计算,从而超时
//事实上只要右边的点检查过一次无法再匹配了,以后就都不行了
}
return false;
}
bool ok(int mid)
{
MM(link,0);
MM(num,0);
for(int u=0;u<n;u++)
{
MM(vis,0);
if(!find_path(u,mid))
return false;
}
return true;
}
int main()
{
while(~scanf("%d %d",&n,&m)&&(n||m))
{
MM(mp,0);
for(int i=0;i<n;i++)
{
scanf("%s",s);
while(~scanf("%c",&c))
{
if(c=='
') break;
scanf("%d",&k);
mp[i][k]=1;
}
}
int l=-1,r=n+1;
while(r-l>1)
{
int mid=(l+r)>>1;
if(ok(mid)) r=mid;
else l=mid;
}
printf("%d
",r);
}
return 0;
}