题意:把n个点,分到m个组中。题目给出每一个点可以被分到的那些组。要求分配完毕后,最大的那一个组的人数最小。
题解:比较怪。一开始化作费用流做。假设每一次增广过后,路径上所有边的费用增大相等的值,这样一来,被增广过的路径下一次就不会被立即增广了。这样就能使与汇点相连的那些点均匀增加。结果悲剧TLE```。
#include <iostream>
using namespace std;
#define MAX 1001
#define INF 999999999
#define min(a,b) (a<b?a:b)
int match[MAX][MAX];
int group[MAX], cnt[MAX];
bool map[MAX][MAX];
bool vis[MAX];
int n, m;
bool find_path ( int u )
{
for ( int i = 1; i <= m; i++ )
{
if ( ! vis[i] && map[u][i] )
{
vis[i] = true;
if ( match[i][0] < group[i] )
{
match[i][++match[i][0]] = u;
return true;
}
for ( int j = 1; j <= match[i][0]; j++ )
if ( find_path ( match[i][j] ) )
{
match[i][j] = u;
return true;
}
}
}
return false;
}
bool Hungary ()
{
memset(match,0,sizeof(match));
for ( int i = 1; i <= n; i++ )
{
memset(vis,0,sizeof(vis));
if ( ! find_path ( i ) )
return false;
}
return true;
}
bool check ( int cap )
{
for ( int i = 1; i <= m; i++ )
group[i] = min ( cap, cnt[i] );
return Hungary ();
}
int main()
{
int l, r, mid, g, i;
char name[20];
while ( scanf("%d%d",&n,&m) && ( n || m ) )
{
memset(map,0,sizeof(map));
memset(cnt,0,sizeof(cnt));
for ( i = 1; i <= n; i++ )
{
scanf("%s",name);
while ( true )
{
scanf("%d",&g);
cnt[g+1]++;
map[i][g+1] = true;
if ( getchar() == '\n' ) break;
}
}
l = 0; r = 1001;
while ( l < r )
{
mid = l + ( r - l ) / 2;
if ( check ( mid ) )
r = mid;
else
l = mid + 1;
}
printf("%d\n",r);
}
//system("pause");
return 0;
}