标签:
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个分组,告诉你每个联系人可以分到哪些分组,且每个联系人只需要分到一个分组即可。现在问所有组的人数中最大的那一个的最小值是多少?
分析:最大值最小用二分来解决,然后我们如何考虑如何在图中验证是否可以满足当前值mid,答案是用最大流来试验。首先超级源点连接每一个联系人节点,负载为1,然后每个联系人连接所以可以被分入的分组节点,负载为1(因为超级源点限制了所以不用拆点),然后所有分组节点连接到超级汇点,负载为mid,表示所有分组容量不超过mid,然后跑最大流,根据结果二分。
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<cstring> #include<string> #include<sstream> using namespace std; const int MAXM = 900000; const int MAXN = 2000; const int INF = 0x3f3f3f3f; struct Edge { int to, cap, next; }; Edge edge[MAXM]; int level[MAXN]; int head[MAXN]; int group[MAXN][MAXN]; int src, des, cnt; void addedge( int from, int to, int cap ) { edge[cnt].to = to; edge[cnt].cap = cap; edge[cnt].next = head[from]; head[from] = cnt++; swap( from, to ); edge[cnt].to = to; edge[cnt].cap = 0; edge[cnt].next = head[from]; head[from] = cnt++; } int bfs( ) { memset( level, -1, sizeof level ); queue<int>q; while (!q.empty( )) q.pop( ); level[src] = 0; q.push( src ); while (!q.empty( )) { int u = q.front( ); q.pop( ); for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > 0 && level[v] == -1) { level[v] = level[u] + 1; q.push( v ); } } } return level[des] != -1; } int dfs( int u, int f ) { if (u == des) return f; int tem; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (edge[i].cap>0 && level[v] == level[u] + 1) { tem = dfs( v, min( f, edge[i].cap ) ); if (tem > 0) { edge[i].cap -= tem; edge[i ^ 1].cap += tem; return tem; } } } level[u] = -1; return 0; } int Dinic( ) { int ans = 0, tem; while (bfs( )) { while ((tem = dfs( src, INF )) > 0) { ans += tem; } } return ans; } int main( ) { int n, m; src = 0; des = 1980; string str; while (cin >> n >> m&&n&&m) { getchar(); for (int i = 1; i <= n; i++) { getline( cin, str ); stringstream ss(str); ss >> str; int g; int num = 0; while (ss >> g) { group[i][++num] = g; } group[i][0] = num; } int low = 0, high = INF - 1; int ans = -1; while (low <= high) { int mid = (low + high) / 2; memset( head, -1, sizeof head ); cnt = 0; for (int i = 1; i <= n; i++) { addedge( src, i, 1 ); } for (int i = 1; i <= m; i++) { addedge( i + 1000, des, mid ); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= group[i][0]; j++) { addedge( i, group[i][j] + 1001, 1 ); } } if (Dinic() < n) low = mid + 1; else { ans = mid; high = mid - 1; } } cout << ans << endl; } return 0; }
解题报告 之 POJ2289 Jamie's Contact Groups
标签:
原文地址:http://blog.csdn.net/maxichu/article/details/45203255