poj3281--网络流 + 拆点

可怜好久没有给自己的博客添加博文了。。

poj3281是一道网络流的题目,也是我写的第二道网络流。参考了别人的代码过了委屈

题意:一个农场主要喂养他的牛, 就给它们做了好多好吃好喝的。但是牛很挑剔,每头牛都只吃特定的食物和喝特定的饮料。问农场主最多能满足多少头牛。

解题思路:这就是个网络流的题目,关键是构图。重点在于将牛分成两个点存。最开始我也不是很理解,后来就明白了。牛的左半边和右半边中间有一条权为1的边,就保证了一头牛只能享用一份食物和饮料。

源码:

//#define LOCAL
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std; 

#define MAXN 500
#define INF 0x7fffffff

int n, f, d;
int map[MAXN][MAXN];
int flow[MAXN][MAXN];
int minflow[MAXN];
int pre[MAXN];

void getmap()
{
	int i, j;
	int a, b;
	int food, drink;
	memset(map, 0, sizeof(map));
	for(i = 1; i <= f; i++) // super src
		map[0][i] = 1;
	for(i = 1; i <= d; i++) // super dest
		map[f + 2* n + i][f + 2 * n + d + 1] = 1;
	for(i = 1; i <= n; i++)
	{
		scanf("%d%d", &a, &b);
		for(j = 1; j <= a; j++) // food -> cow(left)
		{
			scanf("%d", &food);
			map[food][f + i] = 1;
		}
		
		map[f + i][f + n + i] = 1; cow(left) --> cow(right)
		
		for(j = 1; j <= b; j++) // cow(right) --> drink
		{
			scanf("%d", &drink);
			map[f + n + i][f + 2 * n + drink] = 1;
		}
	}
}

int maxflow()
{
	int s, t, cur, u, v, ans = 0;
	s = 0; // src 
	t = f + 2 * n + d + 1; // dest
	
	memset(flow, 0, sizeof(flow));
	while(1)
	{
		memset(pre, -1, sizeof(pre));
		memset(minflow, 0, sizeof(minflow));
		queue<int> q;
		minflow[s] = INF;
		q.push(s);
		while(!q.empty())
		{
			cur = q.front();
			q.pop();
			if(cur == t)
				break;
			for(v = s; v <= t; v++)
			{
				if(pre[v] < 0 && map[cur][v] > flow[cur][v])
				{
					pre[v] = cur;
					minflow[v] = min(map[cur][v] - flow[cur][v], minflow[cur]);
					q.push(v);
				}
			}
		}
		if(pre[t] == -1)
			break;
		for(v = t; v != s; v = pre[v])
		{
			u = pre[v];
			flow[u][v] += minflow[v];
			flow[v][u] -= minflow[v];
		}
		ans += minflow[t];
	}
	return ans; 
}
int main()
{
#ifdef LOCAL
	freopen("poj3281.txt", "r", stdin);
	// freopen(".txt", “w”, stdin);
#endif
	while(scanf("%d%d%d", &n, &f, &d) != EOF)
	{
		getmap();
		printf("%d\n", maxflow());
	}
	return 0;
}
感觉现在我写这种类型的题目思路都比较清晰了,以后自己写的题就会放上详细的题解了,(图文并茂)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值