给你一些名单,和每个名单可以放在哪个分组里,现在要求你把所有的人都分到一个他属于的分组(之一),然后问你分组中最多的那个人数最少是多少...
思路:
二分最多的最少,然后用最大流去判断分组是否合理,建图如下
s 到 所有人连一条边 流量是1
所有分组 到 t 连一条边,流量是mid
然后把所有人和自己属于的分组连边,流量1
跑一边最大流,如果答案等于 N(人数) 那么当前二分满足
up = mid - 1 ........
#include<stdio.h> #include<string.h> #include<queue> #define N_node 1500 + 50 #define N_edge 2000000 + 10000 #define INF 1000000000 using namespace std; typedef struct { int to ,next ,cost; }STAR; typedef struct { int x ,t; }DEP; typedef struct { int a ,b; }EDGE; STAR E[N_edge]; DEP xin ,tou; EDGE edge[N_edge]; int list[N_node] ,tot; int list1[N_node]; int deep[N_node]; char str[1000000]; void add(int a ,int b ,int c) { E[++tot].to = b; E[tot].cost = c; E[tot].next = list[a]; list[a] = tot; E[++tot].to = a; E[tot].cost = 0; E[tot].next = list[b]; list[b] = tot; } int minn(int x ,int y) { return x < y ? x : y; } bool BFS_deep(int s ,int t ,int n) { memset(deep ,255 ,sizeof(deep)); xin.x = s; xin.t = 0; deep[s] = 0; queue<DEP>q; q.push(xin); while(!q.empty()) { tou = q.front(); q.pop(); for(int k = list[tou.x] ;k ;k = E[k].next) { xin.x = E[k].to; xin.t = tou.t + 1; if(!E[k].cost || deep[xin.x] != -1) continue; deep[xin.x] = xin.t; q.push(xin); } } for(int i = 0 ;i <= n ;i ++) list1[i] = list[i]; return deep[t] != -1; } int DFS_flow(int s ,int t ,int flow) { if(s == t) return flow; int nowflow = 0; for(int k = list1[s] ;k ;k = E[k].next) { list1[s] = k; int to = E[k].to; int c = E[k].cost; if(deep[to] != deep[s] + 1 || ! E[k].cost) continue; int tmp = DFS_flow(to ,t ,minn(c ,flow - nowflow)); nowflow += tmp; E[k].cost -= tmp; E[k^1].cost += tmp; if(nowflow == flow) break; } if(!nowflow) deep[s] = 0; return nowflow; } int DINIC(int s ,int t ,int n) { int ans = 0; while(BFS_deep(s ,t ,n)) { ans += DFS_flow(s ,t ,INF); } return ans; } bool ok(int mid ,int tt ,int n ,int m) { memset(list ,0 ,sizeof(list)); tot = 1; int i; for(i = 1 ;i <= n ;i ++) add(0 ,i ,1); for(i = 1 ;i <= m ;i ++) add(n + i ,n + m + 1 ,mid); for(i = 1 ;i <= tt ;i ++) add(edge[i].a ,edge[i].b + n ,1); return DINIC(0 ,n + m + 1 ,n + m + 1) == n; } int main () { int n ,m ,i ,j; while(~scanf("%d %d" ,&n ,&m) && n + m) { getchar(); int tt = 0; for(i = 1 ;i <= n ;i ++) { gets(str); int l = strlen(str) - 1; j = 0; while(str[j] != ' ') j++; int num = 0; for(j++ ;j <= l ;j ++) { if(str[j] == ' ') { edge[++tt].a = i; edge[tt].b = num + 1; num = 0; continue; } num = num * 10 + str[j] - 48; } edge[++tt].a = i; edge[tt].b = num + 1; } int low ,up ,mid; low = 0 ,up = n; int ans; while(low <= up) { mid = (low + up) >> 1; if(ok(mid ,tt ,n ,m)) { ans = mid; up = mid - 1; } else low = mid + 1; } printf("%d " ,ans); } return 0; }