HDU 4292 —— Food(最大流,拆点)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4292


题目意思:店里有N个顾客,F种食物和D种饮料,每个人都会有自己喜欢的食物和饮料,题目中对食物和饮料只有喜欢和不喜欢;店里每种食物和饮料的存货数量不同,顾客消费的标准是同时能分配他喜欢的食物和饮料,分配不到就走人。

在这样的限制下,求最多能分配多少人。

还是比较明显的最大流问题吧。

增加一个源点和一个汇点,源点到每种食物连一条边,容量为该种食物的数量;每种饮料到汇点连一条边,容量为该种饮料的数量。

然后对于每个人,他喜欢的食物就连一条容量1的边到人这里,人再连一条容量1的边到他喜欢的食物,但仅仅这样处理还不行,因为这样可能会使同一个人购买多种食物和饮料,所以还要多加一个限制,就是一个人只能购买1种食物和1种饮料,把1个人拆成两个点,左边用食物连进来,右边连到饮料,两个点之间再连一条容量1的边,这样就能保证每个人只购买1种饮料和1种食物。

然后剩下的就是套最大流算法的工作了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define N 1000
#define pb push_back
const int inf = 0x7fffffff;
struct Edge{
	int from, to, cap, flow;
};
vector<Edge> G;
vector<int> V[N];
void add(int from, int to, int cap){
	G.pb((Edge){from,to,cap,0});
	G.pb((Edge){to,from,0,0});
	int x=G.size();
	V[from].pb(x-2);
	V[to].pb(x-1);
}
int tar, d[N];
bool bfs(){
	memset(d,-1,sizeof(d));
	queue<int> Q;
	Q.push(0);
	d[0]=0;
	while(!Q.empty()){
		int x=Q.front(); Q.pop();
		for(int i=0; i<V[x].size(); i++){
			Edge& e = G[V[x][i]];
			if(d[e.to]==-1 && e.cap>e.flow){
				d[e.to] = d[x]+1;
				Q.push(e.to);
			}
		}
	}
	return (d[tar]!=-1);
}
int cur[N];
int dfs(int u, int v){
	if(u==tar || v==0)	return v;
	int flow=0, f;
	for(int& i=cur[u]; i<V[u].size(); i++){
		int j = V[u][i];
		Edge& e = G[j];
		if(d[e.to]==d[u]+1 && (f=dfs(e.to, min(v, e.cap-e.flow)))>0){
			e.flow+=f;
			flow+=f;
			G[j^1].flow-=f;
			v-=f;
			if(v==0)	break;
		}
	}
	return flow;
}
int MaxFlow(){
	int flow=0;
	while(bfs()){
		memset(cur,0,sizeof(cur));
		flow+=dfs(0,inf);
	}
	return flow;
}
char s[1000];
int main(){
	int n, f, d, v;
	while(~scanf("%d %d %d", &n, &f, &d)){
		tar = n+n+f+d+1;
		for(int i=0; i<=tar; i++)	V[i].clear();
		G.clear();
		for(int i=1; i<=f; i++){
			scanf("%d", &v);
			add(0, i, v);
		}
		for(int i=1; i<=d; i++){
			scanf("%d", &v);
			add(i+f, tar, v);
		}
		char ch;
		for(int i=1; i<=n; i++){
			for(int j=0; j<f; j++){
				ch=getchar();
				while(ch!='Y' && ch!='N')	ch=getchar();
				if(ch=='Y')	add(j+1, i+f+d, 1);
			}
		}
		for(int i=1; i<=n; i++){
			for(int j=0; j<d; j++){
				ch=getchar();
				while(ch!='Y' && ch!='N')	ch=getchar();
				if(ch=='Y')	add(i+f+d+n, j+1+f, 1);
			}
		}
		for(int i=1; i<=n; i++){
			add(i+f+d, i+f+d+n, 1);
		}
		printf("%d\n", MaxFlow());
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值