POJ - 2289 Jamie’s Contact Groups
题意:
有n个人,分为m组,每个可以被归到一些组里,但最终每个人只能归到一个组,求人数最多组的人数最少是多少。
思路:
二分人数,多重匹配判断。
多重匹配:右边的组可以匹配多个左边的人。当每组的人数不够mid的话直接匹配就行。 若已经达到mid,那么看是是否还能寻找到增广路,若能找到就进行替换。
code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn = 1e3 + 5;
struct edge{
int u, v, next;
}g[maxn * maxn * 2];
struct node{
int len, mul[maxn];
} match[maxn];
int head[maxn], cnt;
bool vis[maxn];
void init(int n) {
cnt = 0;
for(int i = 1; i <= n; i++){
head[i] = -1;
}
}
void add(int u, int v){
g[cnt].u = u;
g[cnt].v = v;
g[cnt].next = head[u];
head[u] = cnt++;
}
bool dfs(int u, int mid){ //多重匹配
for(int i = head[u]; i != -1; i = g[i].next) {
int v = g[i].v;
if(vis[v]) continue;
vis[v] = true;
if(match[v].len < mid){
match[v].mul[match[v].len++] = u;
return true;
}
else {
for(int j = 0; j < match[v].len; j++){
if(dfs(match[v].mul[j], mid)){
match[v].mul[j] = u;
return true;
}
}
}
}
return false;
}
bool solve(int n, int m, int mid){
for(int i = 0; i < m; i++) match[i].len = 0;
for(int i = 1; i <= n; i++){
for(int j = 0; j < m; j++) vis[j] = false;
if(!dfs(i, mid)) return false;
}
return true;
}
int main(){
int n, m;
char s[20];
while(scanf("%d%d", &n, &m), n + m) {
init(n);
for(int i = 1; i <= n; i++){
scanf("%s", s);
int u = i, v;
char ch;
while(scanf("%c", &ch), ch != '\n'){
scanf("%d", &v);
add(u, v);
}
}
int l = 0, r = n;
while(l < r) { //二分人数
int mid = (l + r) / 2;
if(solve(n, m, mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", l);
}
}