Poj 3281 最大流入门

就是比二分图匹配多一个, 把牛放中间, 食物和饮料放两边, 然后就是用一个牛拷贝一份, 这样防止多分牛奶或者食物流到同一只牛的地方, 然后每一条边的权值是1





//SPA
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>

#define CLR(arr, val) memset(arr, val, sizeof(arr))
#pragma warning(disable:4996)

using namespace std;

const int MaxV = 10000;
const int MaxE = 10000 << 1;
const int INF = 1e9;

struct Graph
{
	struct Vertex
	{
		int head;
	}V[MaxV];

	struct Edge 
	{
		int v, c, f, next;
		Edge(){}
		Edge(int v,int c, int f, int next):v(v), c(c), f(f), next(next){}
	}E[MaxE];

	void init()
	{
		top = 0;
		CLR(V, -1);
	}
	void addEdge(int u, int v,int w)
	{
		E[top] = Edge(v, w, 0, V[u].head);
		V[u].head = top++;
		E[top] = Edge(u, 0, 0, V[v].head);
		V[v].head = top++;
	}
	int top;
};

int h[MaxV];        //高度
int path[MaxV];     //回路
int gap[MaxV];      //gap优化
int cur[MaxV];      //当前弧优化
int s, t;
int vexNum, edgeNum;
Graph g;

void setHeight()
{
	CLR(gap, 0);
	CLR(h, -1);
	h[t] = 0;

	queue<int>Q;
	Q.push(t);
	while(!Q.empty())
	{
		int top = Q.front();
		gap[ h[top] ]++;
		for(int i = g.V[top].head; i != -1; i = g.E[i].next)
		{
			int v = g.E[i].v;
			if(h[v] == -1)
			{
				h[v] = h[top] + 1;
				Q.push(v);
			}
		}
		Q.pop();
	}
}

int sap()
{
	setHeight();
	int maxFlow = 0, u = s;
	int flow = INF;
	for(int i = 0; i <= vexNum; i++)
		cur[i] = g.V[i].head;
	while(h[s] < vexNum)
	{
		int &i = cur[u];
		for(; i != -1; i = g.E[i].next)
		{
			int v = g.E[i].v;
			if(g.E[i].c > g.E[i].f && h[u] == h[v] + 1)
			{
				u = v;
				path[v] = i;
				flow = min(flow, g.E[i].c - g.E[i].f);
				if(u == t)
				{
					while(u != s)
					{
						int j = path[u];
						g.E[j].f += flow;
						g.E[j ^ 1].f -= flow;
						u = g.E[j ^ 1].v;
					}
					maxFlow += flow;
					flow = INF;
				}
				break;
			}
		}

		if(i == -1)
		{
			if(--gap[ h[u] ] == 0)
				break;
			int minH = vexNum - 1;
			cur[u] = g.V[u].head;
			for(int j = g.V[u].head; j != -1; j = g.E[j].next)
				if(g.E[j].c > g.E[j].f)
					minH = min(minH, h[g.E[j].v]);
			h[u] = minH + 1;
			++gap[ h[u] ];
			if(u != s)
				u = g.E[path[u] ^ 1].v;
		}
	}
	return maxFlow;	
}

int N, F, D;


void buildMap()
{
	for(int i = 1; i <= F; i++)
		g.addEdge(0, i, 1);
	for(int i = F + 1; i <= F + N; i++)
		g.addEdge(i, i + N, 1);
	for(int i = F + N * 2 + 1; i <= F + N * 2 + D; i++)
		g.addEdge(i, vexNum, 1);
	int f, d;
	for(int i = 1; i <= N; i++) //n头牛
	{
		scanf("%d %d", &f, &d);
		while(f--)
		{
			int v;
			scanf("%d", &v);
			g.addEdge(v, F + i, 1);
		}
		while(d--)
		{
			int v;
			scanf("%d", &v);
			g.addEdge(F + N + i, F + 2* N + v, 1);
		}
	}

}

int main()
{
	while(scanf("%d %d %d", &N, &F, &D) != EOF)
	{
		g.init();
		vexNum = F + 2 * N + D + 1;
		buildMap();
		
		s = 0, t = vexNum;
		printf("%d\n", sap());
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值