1. 程式人生 > 實用技巧 >POJ-3281 Dining(最大流)(拆點)

POJ-3281 Dining(最大流)(拆點)

題意:牧場主為N只牛(1 <= N <= 100)準備了a(1 <= a <= 100)種可以吃的和b(1 <= b <= 100)種可以喝的。每隻牛的克隆體都有各自喜歡的食物和飲料,而每種食物或飲料只能分配給一隻牛,最多有多少隻牛可以同時得到喜歡的食物和飲料?

分析:一隻牛隻要獲得它的喜歡清單中的一種食物和一種飲料就滿足了,求最大的牛的數量。我們一種直觀的想法是\(源---食物---牛---飲料---匯點\),但是這樣會有一個如下的問題。
就是,從源頭提供的食物會經過綠色的邊分叉,這樣一隻牛可以攜帶多份食物到達終點,我們可以把一隻牛拆成兩點,在中間加一條\(容量為1\)

的邊,這樣從左邊過來的食物只能有一種。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int inf = 1 << 29, N = 50005, M = 300005;
int h[N], e[M], ne[M], d[N];
int w[M];

int m, s, t, idx, maxflow;

//n只牛,a種吃的,b種喝的
int n, a, b;

void add(int a, int b, int c)
{
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
	e[idx] = a, w[idx] = 0, ne[idx] = h[b], h[b] = idx++;
}

//構造分層圖
bool bfs()
{
	memset(d, 0, sizeof d);
	queue<int> q;
	q.push(s), d[s] = 1;
	while (q.size())
	{
		int u = q.front();
		q.pop();
		for (int i = h[u]; i != -1; i = ne[i])
		{
			int j = e[i];
			if (w[i] && !d[j])
			{
				q.push(j);
				d[j] = d[u] + 1;
				if (j == t) return true;
			}
		}
	}
	return false;
}

//在分層圖上增廣
int dinic(int u, int flow)
{
	if (u == t) return flow;
	int rest = flow, k;

	for (int i = h[u]; i != -1 && rest; i = ne[i])
	{
		int j = e[i];
		if (w[i] && d[j] == d[u] + 1)
		{
			k = dinic(j, min(rest, w[i]));
			//增廣完畢
			if (!k) d[j] = 0;
			w[i] -= k;
			w[i ^ 1] += k;
			//剩餘容量
			rest -= k;
		}
	}
	//返回流過的值
	return flow - rest;
}

int main()
{
	
	scanf("%d%d%d", &n, &a, &b);

	memset(h, -1, sizeof h);
	s = 0, t = a + n + n + b + 1;
	for (int i = 1; i <= n; ++i)
	{
		int f, d;
		scanf("%d%d", &f, &d);
		int u;
		for (int j = 1; j <= f; ++j)
		{
			scanf("%d", &u);
			add(u, a + i, 1);
		}

		for (int j = 1; j <= d; ++j)
		{
			scanf("%d", &u);
			add(a + n + i, a + n + n + u, 1);
		}
		add(a + i, a + n + i, 1);
	}

	for (int i = 1; i <= a; ++i)
	{
		add(0, i, 1);
	}

	for (int i = 1; i <= b; ++i)
	{
		add(a + n + n + i, t, 1);
	}
	
	int flow = 0;
	while (bfs())
	{
		while (flow = dinic(s, inf)) maxflow += flow;
	}

	printf("%d\n", maxflow);

	return 0;
}