pku 1815
pku 2987

pku 2289

Tuz posted @ 2009年9月11日 17:19 in acm练习 , 1612 阅读

思路:二分最大组的人数,建图,然后求最大流,sap实在强大,呵呵。

代码:

 

#include <stdio.h>
#include <string.h>
#define oo 0x7fffffff
#define MAXN 1508
typedef struct
{
	int u; int v; int cap; int next;
}edge_t;
edge_t e[MAXN * MAXN];
char adj[1002][502];
int first[MAXN];
int dist[MAXN];
int now[MAXN];
int pre[MAXN];
int cnt[MAXN];
int cur[MAXN];
int in[502];
int tot, st, ed;
int n2, n, m;
void add(int u, int v, int cap)
{
	e[++tot].u = u; e[tot].v = v; e[tot].cap = cap; e[tot].next = first[u]; first[u] = tot;
	e[++tot].u = v; e[tot].v = u; e[tot].cap = 0;   e[tot].next = first[v]; first[v] = tot;
}
int init()
{
	char ch;
	int i, j;
	scanf("%d %d", &n, &m);
	if(n == 0 && m == 0) return 0;
	memset(adj, 0, sizeof(adj));
	memset(in, 0, sizeof(in));
	st = 0; ed = n + m + 1; n2 = n;
	getchar();
	for(i = 1;i <= n; i++)
	{
		ch = getchar();
		while((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) ch = getchar();
		while(ch == ' ') ch = getchar();
		while(1)
		{
			j = 0;
			while(ch >= '0' && ch <= '9')
			{
				j = j * 10 + ch - '0';
				ch = getchar();
			}
			adj[i][j + 1] = 1;
			in[j + 1]++;
			if(ch == '\n') break;
			while(ch == ' ') ch = getchar();
		}
	}
	n = n + m + 2;
	return 1;
}
void build(int lmt)
{
	int i, j;
	memset(first, -1, sizeof(first)); tot = -1;
	for(i = 1;i <= n2; i++)
	{
		add(st, i, 1);
		for(j = 1;j <= m; j++) if(adj[i][j] == 1) add(i, n2 + j, 1);
	}
	for(i = 1;i <= m; i++)
		if(in[i] > lmt) add(i + n2, ed, lmt);
		else add(i + n2, ed, in[i]);
}
int sap()
{
	int tot_flow;
	int now_flow, found, min;
	int i, j, t;
	memset(dist, 0, sizeof(dist));
	memset(now, -1, sizeof(now));
	memset(cnt, 0, sizeof(cnt));
	i = st;
	tot_flow = 0; now_flow = oo;
	cnt[0] = n;
	while(dist[st] < n)
	{
		cur[i] = now_flow; found = 0;
		if(now[i] == -1) t = first[i];
		else t = now[i];
		while(t != -1)
		{
			j = e[t].v;
			if(e[t].cap > 0 && dist[j] + 1 == dist[i])
			{
				found = 1; now[i] = t;
				if(e[t].cap < now_flow) now_flow = e[t].cap;
				pre[j] = t; i = j;
				if(i == ed)
				{
					tot_flow += now_flow;
					while(i != st)
					{
						e[pre[i]].cap -= now_flow;
						e[pre[i]^1].cap += now_flow;
						i = e[pre[i]].u;
					}
					now_flow = oo;
				}
				break;
			}
			t = e[t].next;
		}
		if(found) continue;
		if(--cnt[dist[i]] == 0) break;
		min = n - 1;
		t = first[i];
		while(t != -1)
		{
			if(e[t].cap > 0 && dist[e[t].v] < min)
			{
				min = dist[e[t].v];
				now[i] = t;
			}
			t = e[t].next;
		}
		dist[i] = min + 1;
		cnt[dist[i]]++;
		if(i != st)
		{
			i = e[pre[i]].u;
			now_flow = cur[i];
		}
	}
	return tot_flow;
}
void solve()
{
	int high = n2;
	int low = 0;
	int mid;
	int res;
	while(low < high)
	{
		mid = (low + high) >> 1;
		build(mid);
		res = sap();
		if(res >= n2) high = mid;
		else low = mid + 1;
	}
	printf("%d\n", low);
}
int main()
{
	while(init()) solve();
	return 0;
}

 

 

qinpengfei 说:
2010年10月23日 16:36

为什么我二分用dinic求最大流一直wa啊 求助


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter