题目大意是给你一堆联系人, 每个人有几个标签, 然后让你将他们分组(每组里的人要标签相同), 问其中人最多的组的人数最少是多少.
有点像鸽巢的感觉...开始我想了一个, 以为是每次求最大匹配, 然后把已盖点的邻边全删掉, 然后看能求几次最大匹配....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()); } }