题意:杰米想给手机里面的联系人分组,问最大分组中的规模最小,给了每个联系人可能所在组的编号;
思路:显然是一个多重匹配问题,x(联系人),y(组编号);一般来说,对最大限制的选取(这里是“最大分组中的规模最小”)通常采用二分搜索来降低搜索空间;具体搜索做法和Hungary()差不多,变的就是cy[maxn]变成cy[maxn][maxn],同时用num[i]来表示与y[i]匹配的x[...]的数目,cy[i][j]表示与y[i]匹配的第j个元素(x);
算法流程入下:
(1)从G = (X,Y;E)中选取一个初始匹配M。设置初始搜索的上限和下限(二分值)。
(2)对最大限制n进行二分搜索。知道下限值大于上限值。
(3)若X中的点全部被M匹配,说明可以达到一个多重匹配,转至步骤(2);否则若与元素y[i]匹配的数目num[i] < n,则将x[i]与y[i]进行匹配。
(4)如果与y[i]匹配的元素已经达到上限,那么在与y[i]匹配的元素中选者一个元素,检查是否能找到一条增广路径,如果能,则让出位置,让x[i]与y[i]匹配。转至步骤(2)。
/*****************************************
Author :Crazy_AC(JamesQi)
Time :2015
File Name :
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
using namespace std;
#define MEM(a,b) memset(a,b,sizeof a)
#define pk push_back
template<class T> inline T Get_Max(const T&a,const T&b){return a < b?b:a;}
template<class T> inline T Get_Min(const T&a,const T&b){return a < b?a:b;}
typedef long long ll;
typedef pair<int,int> ii;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1010;
const int maxm = 510;
int uN,vN;
int g[maxn][maxm];
int link[maxm][maxm];
bool vis[maxm];
int num[maxm];
bool dfs(int u){
for (int v = 0;v < vN;v++){
if (g[u][v] && !vis[v]){
vis[v] = true;
if (link[v][0] < num[v]){
link[v][++link[v][0]] = u;
return true;
}
for (int i = 1;i <= num[0];i++){
if (dfs(link[v][i])){
link[v][i] = u;
return true;
}
}
}
}
return false;
}
int Hungary(){
int ret = 0;
for (int i = 0;i < vN;i++)
link[i][0] = 0;
for (int u = 0;u < uN;u++){
MEM(vis, false);
if (dfs(u)) ret++;
}
return ret;
}
char str[10000];
char name[100];
int main()
{
// ios::sync_with_stdio(false);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(scanf("%d%d",&uN,&vN) == 2){
if (uN == 0 && vN == 0) break;
MEM(g, 0);
gets(str);
// fgets(str,10000,stdin);
for (int i = 0;i < uN;i++){
gets(str);
// fgets(str,10000,stdin);
int v;
char *p = strtok(str," ");
sscanf(p,"%s",name);
p = strtok(NULL," ");
while(p != NULL){
sscanf(p,"%d",&v);
g[i][v] = 1;
p = strtok(NULL," ");
}
}
int ans;
int l = 1,r = uN;
while(l <= r){
int mid = (l + r) >> 1;
for (int i = 0;i < vN;i++)
num[i] = mid;
if (Hungary() >= uN){
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
printf("%d\n",ans);
}
return 0;
}