poj 3281 Dining(最大流)

版权声明:本文为博主原创文章,转载请附带博主链接。 https://blog.csdn.net/pashuihou/article/details/89303720

【题目链接】
http://poj.org/problem?id=3281

题目意思

有F中食物,D种饮料,n头牛。每种牛吃不同种类的食物和饮料,每种食物
饮料只能一只牛吃,问最多满足多少头牛?

解题思路

把食物和饮料分两边,一头牛分成两个点放中间,容量为1.最后建立两个虚点

代码部分

include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <string>
#include <map>
using namespace std;
#define inf 0x3f3f3f3
#define LL long long
#define pii pair<int ,int>
const int N = 450;
int n,f,d,maxflow;
int mp[N][N];  
int dis[N];   //
int cnt[N];  //0为源点, 2*n+f+d+1为汇点 
bool ok;
void init()  //初始化 
{
	memset(dis,0,sizeof(dis));
	cnt[0] = 2*n+f+d+2;  //设置源点流为无限大 
	int i = 1;
	memset(mp,0,sizeof(mp));
	for(; i <= f; i++)   //源点到食物的权值为1 
		mp[0][i] = 1;
	for (; i <= n+f; i++)  //把牛拆成两点,之间的权值也为1 
		mp[i][i+n] = 1;
	for (i = 1+2*n+f; i <= 2*n+d+f; i++) //饮料与汇点的权值为1 
		mp[i][2*n+d+f+1] = 1;
}
int Sap(int s,int mflow) //现在点的编号,最小的流 
{
	int midis;
	if (s == 2*n+f+d+1)  
	{
		ok = true;
		maxflow += mflow;
		return mflow;
	}
	midis = 2*n+f+d; //可流边的最小编号 
	for (int i = 0; i <= 2*n+f+d+1; i++)
	{
		if (mp[s][i] > 0)
		{
			if (dis[s] == dis[i]+1)
			{
				int flow = Sap(i,min(mflow,mp[s][i]));
				if (ok){
					mp[s][i] -= flow;
					mp[i][s] += flow;
					return flow;
				}
			}
			midis = min(midis,dis[i]);
		}
	}
	//GAP优化 
	cnt[dis[s]]--;
	if (cnt[dis[s]] == 0) dis[0] = 2*n+f+d+1;
	dis[s] = midis + 1;
	cnt[dis[s]]++;
}
int main()
{
	while (~scanf("%d %d %d",&n,&f,&d))
	{
		init();
		int ff,dd,vf,vd;
		for (int i = 1; i <= n; i++)
		{
			scanf("%d %d",&ff,&dd);
			for (int j = 0; j < ff; j++)
			{
				scanf("%d",&vf);
				mp[vf][i+f] = 1;  //食物与牛1 
			}
			for (int j = 0; j < dd; j++)
			{
				scanf("%d",&vd);
				mp[i+n+f][2*n+f+vd] = 1;  //饮料与牛2	
			} 
		}
		maxflow = 0;
		while (dis[0] < 2*n+f+d+1)
		{
			ok = false;
			Sap(0,inf);
		}
		printf("%d\n",maxflow);
	}
	return 0; 
}

猜你喜欢

转载自blog.csdn.net/pashuihou/article/details/89303720