2240. 餐饮

题目链接

2240. 餐饮

奶牛们在吃饭方面十分挑剔。

每头奶牛都有自己喜欢的食物和饮料,并且不会食用其他不喜欢的食物和饮料。

农夫约翰为他的奶牛们做了美味的饭菜,但他忘了对照他们的喜好来检查菜单。

虽然他可能无法令所有奶牛满意,但他想给尽可能多的奶牛提供一顿完整的用餐----既有食物可吃,也有饮料可喝。

农夫约翰一共烹制了 \(F\) 种食物,并提供了 \(D\) 种饮料。

约翰共有 \(N\) 头奶牛,其中第 \(i\) 头奶牛有 \(F_i\) 种喜欢的食物以及 \(D_i\) 种喜欢的饮料。

约翰需要给每头奶牛分配一种食物和一种饮料,并使得有吃有喝的奶牛数量尽可能大。

每种食物或饮料都只有一份,所以只能分配给一头奶牛食用(即,一旦将第 \(2\) 种食物分配给了一头奶牛,就不能再分配给其他奶牛了)。

输入格式

第一行包含三个整数 \(N,F,D\)

接下来 \(N\) 行,其中第 \(i\) 行描述第 \(i\) 头奶牛的饮食喜好,首先包含两个整数 \(F_i\)\(D_i\),表示其喜欢的食物和饮料数量,然后包含 \(F_i\) 个整数表示其喜欢的食物的种类编号,最后包含 \(D_i\) 个整数表示其喜欢的饮料的种类编号。

食物编号从 \(1\)\(F\),饮料编号从 \(1\)\(D\)

输出格式

输出一个整数,表示能够有吃有喝的奶牛的最大数量。

数据范围

\(1 \le N,F,D \le 100\),
\(1 \le F_i \le F\),
\(1 \le D_i \le D\)

输入样例:

4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3

输出样例:

3

样例解释

一种使得三头奶牛满意的可行方法是:

奶牛 \(1\):没饭。
奶牛 \(2\):食物 \(2\),饮料 \(2\)
奶牛 \(3\):食物 \(1\),饮料 \(1\)
奶牛 \(4\):食物 \(3\),饮料 \(3\)

解题思路

最大流,拆点

建图:左边为食物,中间为奶牛,右边为饮料,对于每一奶牛,向左边它喜欢的食物建反向边,向右边它喜欢的饮料建边,容量都为 \(1\),建立源点 \(S\),其连向所有的事物,建立汇点 \(T\),所有的饮料连向 \(T\),所有的容量都为 \(1\),但这样会有问题,可能会有好多流量经过同一个奶牛表示的点,可以对这部分的点拆点,即一分为二,食物连向入点,出点连向饮料,入点连向出点,且容量为 \(1\),这样即可保证最多只能有一条流量经过一个奶牛表示的节点,求解的最大流即为答案。\(\color{red}{为什么?}\)不难发现,每条路径不可能经过同一个点,正好对应每种食物和饮料只能使用一次,且经过的中间的点即为使用者

  • 时间复杂度:\(O(n^2m)\)

代码

// Problem: 餐饮
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2242/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=105*4,M=(205+105+200*100)*2,inf=1e8;
int n,F,D,S,T;
int h[N],e[M],f[M],ne[M],idx;
int hh,tt,q[N],cur[N],d[N];
void add(int a,int b,int c)
{
	e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
	e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}
bool bfs()
{
	memset(d,-1,sizeof d);
	hh=tt=d[S]=0;
	q[0]=S;
	cur[S]=h[S];
	while(hh<=tt)
	{
		int x=q[hh++];
		for(int i=h[x];~i;i=ne[i])
		{
			int y=e[i];
			if(d[y]==-1&&f[i])
			{
				d[y]=d[x]+1;
				cur[y]=h[y];
				if(y==T)return true;
				q[++tt]=y;
			}
		}
	}
	return false;
}
int dfs(int x,int limit)
{
	if(x==T)return limit;
	int flow=0;
	for(int i=cur[x];~i&&flow<limit;i=ne[i])
	{
		cur[x]=i;
		int y=e[i];
		if(d[y]==d[x]+1&&f[i])
		{
			int t=dfs(y,min(f[i],limit-flow));
			if(!t)d[y]=-1;
			f[i]-=t,f[i^1]+=t,flow+=t;
		}
	}
	return flow;
}
int dinic()
{
	int res=0,flow;
	while(bfs())while(flow=dfs(S,inf))res+=flow;
	return res;
}
int main()
{
	memset(h,-1,sizeof h);
    scanf("%d%d%d",&n,&F,&D);
    S=0,T=2*n+F+D+1;
    for(int i=1;i<=F;i++)add(S,2*n+i,1);
    for(int i=1;i<=D;i++)add(2*n+F+i,T,1);
    for(int i=1;i<=n;i++)
    {
    	int f,d;
    	scanf("%d%d",&f,&d);
    	add(i,n+i,1);
    	int x;
    	while(f--)
    	{
    		scanf("%d",&x);
    		add(2*n+x,i,1);
    	}
    	while(d--)
    	{
    		scanf("%d",&x);
    		add(n+i,2*n+F+x,1);
    	}
    }
    printf("%d",dinic());
    return 0;
}
posted @ 2022-11-26 19:16  zyy2001  阅读(30)  评论(0编辑  收藏  举报