2240. 餐饮

题目链接

2240. 餐饮

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

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

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

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

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

约翰共有 N 头奶牛,其中第 i 头奶牛有 Fi 种喜欢的食物以及 Di 种喜欢的饮料。

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

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

输入格式

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

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

食物编号从 1F,饮料编号从 1D

输出格式

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

数据范围

1N,F,D100,
1FiF,
1DiD

输入样例:

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,这样即可保证最多只能有一条流量经过一个奶牛表示的节点,求解的最大流即为答案。不难发现,每条路径不可能经过同一个点,正好对应每种食物和饮料只能使用一次,且经过的中间的点即为使用者

  • 时间复杂度:O(n2m)

代码

// 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; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16928105.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2021-11-26 匈牙利算法
2021-11-26 染色法判定二分图
点击右上角即可分享
微信分享提示