您的位置:首页 > 其它

POJ 2289 Jamie's Contact Groups 多重匹配+二分

2012-08-05 18:18 423 查看
题目大意是给你一堆联系人, 每个人有几个标签, 然后让你将他们分组(每组里的人要标签相同), 问其中人最多的组的人数最少是多少.

有点像鸽巢的感觉...开始我想了一个, 以为是每次求最大匹配, 然后把已盖点的邻边全删掉, 然后看能求几次最大匹配....WA之...

其实显然是错的, 因为每次删去一堆边你不能保证这样的匹配是最优的.

然后发现有多重匹配这种东西....其实也就是给定{V}最多能匹配多少个u, 然后求最大匹配.

用 flag[v][k] 表示点v匹配到第k个点. >=0表示匹配的点是u =  flag[v][k]. <0表示还未匹配到第k点.

对已经匹配满k个点的情况, dfs里要枚举v匹配的这k个u, 然后看有没有增广路, 有的话让出匹配.

这样, 二分答案就能求出最少是多少, 二分条件是 最大匹配是否等于人数(表示这样的限度是否足够容纳所有人).

貌似也可以用最大流+二分做.但是肯定是匹配好写点

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef long long int64;
#define INF (1<<30)
#define bug(s) cout<<#s<<"="<<s<<" "

// 1/ 多重匹配, v能匹配多个u.
// 2/ 指定每个v的匹配上限k, 若最大匹配=u. 则说明k足够大. 从而可以二分答案.

#define MAXN 1002
#define MAXM 502
#define MAXE MAXN*MAXM //最大边数
struct node
{
int u, v, w;
}a[MAXE];
int fa[MAXN], next[MAXE], idx;
int flag[MAXM][MAXN];
int tot[MAXM]; //tot[v] 表示v已经匹配的u数目
int vis[MAXM]; //dfs访问标记, 只用vis[v]. u是枚举一遍的.
int n, m;

void addedge(int u, int v, int w) { a[idx].u=u; a[idx].v=v; a[idx].w=w; next[idx]=fa[u]; fa[u]=idx++; }

int dfs(int u, int k) //匹配k
{
for(int e = fa[u]; e!=-1; e=next[e])
{
int v = a[e].v;
if(vis[v]) continue;
vis[v] = 1;
if(tot[v]<k) //tot[v]<k, 未满
{
flag[v][tot[v]++] = u;
return 1;
}
FOR(i, 0, k-1) //tot[v]=k, 满
if(dfs(flag[v][i], k))
{
flag[v][i] = u;
return 1;
}
}
return 0;
}

void print()
{
FOR(i, 1, m)
{
bug(i);bug(tot[i])<<endl;
}
}

int hungry(int k)
{
int ans = 0;
memset(flag, 0, sizeof(flag));
memset(tot, 0, sizeof(tot));
FOR(u, 1, n)
{
memset(vis, 0, sizeof(vis));
if(dfs(u, k))
ans++;
}
//bug(k)<<endl;
//print();
return ans;
}

int solve()
{
int l = 1, r = n; //每组几个人
while(l<r) //当 l==r跳出
{
int mid = (l+r)>>1;
if(hungry(mid) == n)
r = mid;
else
l = mid+1;
}
return l;
}

int main()
{
while(scanf("%d%d", &n, &m) == 2)
{
if(!n && !m) break;
idx = 0;
memset(fa, -1, sizeof(fa));
FOR(i, 1, n)
{
//bug(i);
char buf[20];
scanf("%s", buf);
int v;
char ch;
while(scanf("%d%c", &v, &ch) == 2)
{
//bug(v);bug(ch)<<endl;
v++; //1-th
addedge(i, v, 1);
if(ch == '\n') break;
}
}
printf("%d\n", solve());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  struct c