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