NYOJ 326 && POJ 3281 Dining (网络流)

NYOJ题目连接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=326

POJ题目连接:http://poj.org/problem?id=3281

把牛的编号拆开,建边权值为1,避免一头牛选双份食物和饮料,建立一个超级源点并与所有食物编号建边,建立一个超级汇点并与所有饮料编号建边,求最大流即可。

参考代码:

 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define NN 405
#define MM 40500
#define CLR(arr,v) memset(arr,v,sizeof(arr))

int map[NN][NN],pre[NN],gap[NN],cnt[NN],stck[NN],top;
int que[NN],head,total;
bool vis[NN],flag;
int h[NN],num[MM],nex[MM],pos;
int FF[NN],DD[NN];

void init()
{
	CLR(map,0); CLR(gap,0); CLR(cnt,0); 
	CLR(stck,0);CLR(que,0); CLR(nex,0);
	CLR(vis,0); CLR(num,0); CLR(h,0); 
	pos = top = 0; flag = false;
}

void add(int u,int v)
{
	num[++pos] = v;
	nex[pos] = h[u];
	h[u] = pos;
}

void init_gap(int n)
{
	head = total = 0;
	que[total++] = n;
	vis[n] = true;
	cnt[0] = 1;
	while(head < total)
	{
		int p = que[head++];
		if(head >= NN) head -= NN;
		for(int i = h[p]; i ;i = nex[i])
		{
			if(!vis[ num[i] ])
			{
				vis[ num[i] ] = true;
				gap[ num[i] ] = gap[ p] + 1;
				cnt[ gap[num[i]] ]++;
				que[total++] = num[i];
				if(total >= NN) total -= NN;
			}
		}
	}
}

bool dfs(int p,int t)
{
	for(int i = h[p]; i ;i = nex[i])
	{
		if(gap[p] - gap[ num[i] ] == 1 && map[p][ num[i] ] > 0)
		{
			pre[ num[i] ] = p;
			if(num[i] != t) stck[++top] = num[i];
			if(num[i] == t || dfs(num[i],t)) return true;
		}
	}
	cnt[ gap[p] ]--;
	cnt[ gap[p]+1 ]++;
	top--;
	if(cnt[ gap[p] ] == 0) flag = true;
	gap[p] += 1;
	return false;
}

int MaxFlow(int s,int t)
{
	init_gap(t);
	int res = 0;
	stck[top] = s;
	while(!flag)
	{
		CLR(pre,-1);
		if(top < 0) top = 0;
		if(!dfs(stck[top],t)) continue;
		int p = t;
		res += 1;
		while(pre[p] != -1)
		{
			map[ pre[p] ][p] -= 1;
			map[p][ pre[p] ] += 1;
			p = pre[p];
		}
		top = 0;
	}
	return res;
}
int main()
{
	int F,N,D;
	while(~scanf("%d%d%d",&N,&F,&D))
	{
		init();
		int s = 0,f,d;
		for(int i = 1;i <= N;++i)
		{
			map[i][i+N+F+D] = 1;
			scanf("%d%d",&f,&d);
			for(int j = 0;j < f;++j)
				scanf("%d",&FF[j]);
			for(int k = 0;k < d;++k)
				scanf("%d",&DD[k]);
			if(f == 0 || d == 0) continue;
			for(int j = 0;j < f;++j)
				map[ FF[j]+N ][i] = 1;
			for(int j = 0;j < d;++j)
				map[i+N+F+D][ DD[j]+N+F ] = 1;
		}
		int n = F + N * 2 + D + 1;
		for(int i = F + N + 1,j = 1;j <= D;++j,++i)		
			map[i][n] = 1;
		for(int i = N + 1,j = 1;j <= F;++j,++i)
			map[0][i] = 1;

		for(int i = 0;i <= n;++i)
		{
			for(int j = 0;j <= n;++j)
				if(map[i][j]) 
				{
					add(i,j);
					add(j,i);
				}
		}
		printf("%d\n",MaxFlow(s,n));
	}
	return 0;
}        


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值