Time Limit: 7000MS | Memory Limit: 65536K | |
Total Submissions: 6902 | Accepted: 2261 |
Description
Input
Output
Sample Input
3 2 John 0 1 Rose 1 Mary 1 5 4 ACM 1 2 3 ICPC 0 1 Asian 0 2 3 Regional 1 2 ShangHai 0 2 0 0
Sample Output
2 2
题意:有 n 个人 , m 个组(0 ~ m - 1)。每个人只能选择一个组,现在给出每个人可以选择的组号,设拥有人数最多的小组有 sum个人,问sum的最小值。
解析:要求最大值的最小化,第一反应就是用二分查找。二分枚举人最多的小组拥有的人数mid。
首先构造网络流, 建立超级源点, 超级汇点。
源点到每个人建边,权值为1。
每个人到可选择的小组建边,权值为1。
每个小组到汇点建边,权值为mid。
每次跑一遍网络流,如果满流的话,人数最多的小组拥有 mid 人,这种情况是可能存在的,如果当前大值的最小值 < mid, 更新最大值的最小值。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define maxn 2000 #define maxm 1000000 #define INF 0x3f3f3f3f using namespace std; int n, m; struct node { int u, v, cap, flow, next; }; node edge[maxm]; node newedge[maxm]; int head[maxn], cnt; int newhead[maxn], newcnt; int cur[maxn]; int dist[maxn], vis[maxn]; void init(){ cnt = 0; memset(head, -1, sizeof(head)); } void add(int u, int v, int w){ node E; edge[cnt] = {u, v, w, 0, head[u]}; head[u] = cnt++; edge[cnt] = {v, u, 0, 0 ,head[v]}; head[v] = cnt++; } void getmap(){ char str[100]; for(int i = 1; i <= n; ++i){ add(0, i, 1);//源点到每个人建边,权值为1 scanf("%s", str); int a; while(getchar() != '\n'){ scanf("%d", &a); add(i, a + 1 + n, 1);//每个人到对应的组建边,权值为1 } } } bool BFS(int st ,int ed){ queue<int>q; memset(vis, 0 ,sizeof(vis)); memset(dist, -1, sizeof(dist)); vis[st] = 1; dist[st] = 0; q.push(st); while(!q.empty()){ int u = q.front(); q.pop(); for(int i = head[u]; i != -1; i = edge[i].next){ node E = edge[i]; if(!vis[E.v] && E.cap > E.flow){ vis[E.v] = 1; dist[E.v] = dist[u] + 1; if(E.v == ed) return true; q.push(E.v); } } } return false; } int DFS(int x, int ed, int a){ if(x == ed || a == 0) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i = edge[i].next){ node &E = edge[i]; if(dist[E.v] == dist[x] + 1 && (f = DFS(E.v, ed, min(a, E.cap - E.flow))) > 0){ E.flow += f; edge[i ^ 1].flow -= f; a -= f; flow += f; if(a == 0) break; } } return flow; } int maxflow(int st, int ed){ int flowsum = 0; while(BFS(st,ed)){ memcpy(cur, head, sizeof(head)); flowsum += DFS(st, ed, INF); } return flowsum; } int main(){ while(scanf("%d%d", &n, &m), n || m){ init(); getmap(); memcpy(newhead, head, sizeof(head)); memcpy(newedge, edge, sizeof(edge)); newcnt = cnt; int l = 0, r = n, mid; int ans = n; while(r >= l){ memcpy(head, newhead, sizeof(newhead)); memcpy(edge, newedge, sizeof(newedge)); cnt = newcnt; mid = (l + r) / 2; for(int i = 1 ;i <= m; ++i){ add(i + n, n + m + 1, mid);//每个组向汇点建边 } if(maxflow(0, n + m + 1) == n){ ans = min(ans, mid); r = mid - 1; } else l = mid + 1; } printf("%d\n", ans); } return 0; }