[Luogu P2891/POJ 3281/USACO07OPEN ]吃饭Dining
传送门:https://www.luogu.org/problemnew/show/P2891
题面
\
Solution
网络流
先引用一句真理:网络流最重要的就是建模
今天这道题让我深有体会
首先,观察数据范围,n=100,一般这种100-1000的图论题,很有可能是网络流.
那就直接从网络流的角度入手
考虑这样建模

建模要点如下:
1.建权值为1的边,保证每个食物和水仅用一次
2.没了
对以上的图求一个最大流,那不就是我们想要的最大的匹配数吗?
看起来是不是很OjbK?
其实不然,这样子一头牛有可能脚踏N条食物和水,但是题目要求一头牛只能吃喝一次
反例如下:

所以说,我们要对一头牛吃的东西做一个限制,保证其只流过1
怎么限制呢?
直接把一头牛拆成两头牛,中间连一条边就OK了嘛
如下图:

接下来就可以考虑如何给点编号了
我的编号方法很直接,很暴力
源点:1
食物: 2 ~ 2+f-1
牛 2+f ~ 2+f+2n -1
水: 2+f+2n ~ 2+f+2n+d
汇点:1000
如下图所示

按照以上方法,每种物品对应的点为:
食物i : 1+i
牛i : 1+f+i
牛i的右边的分点: 1+f+n+i
水i: 1+f+2*n+i
然后dinic直接求一波最大流就可以带走啦
DINIC教程传送门: http://www.cnblogs.com/SYCstudio/p/7260613.html (个人感觉写得很清楚)
Code
//Luogu P2891 [USACO07OPEN]吃饭Dining
//Apr,2ed,2018
//Dinic求最大流
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=100+10;
const int M=N*10;
const int inf=0x3f3f3f3f;
struct line
{
int t,rev,w;
};
vector <line> e[M];
inline void AddLine(int s,int t)
{
line temp;
temp.t=t,temp.rev=e[t].size(),temp.w=1;
e[s].push_back(temp);
temp.t=s,temp.rev=e[s].size()-1,temp.w=0;
e[t].push_back(temp);
}
int n,f,d;
int dl[M],head,tail,depth[M];
bool visited[M];
bool bfs()
{
memset(visited,0,sizeof visited);
dl[1]=1,depth[1]=1;
visited[1]=true;
head=1,tail=2;
while(head<tail)
{
int now=dl[head],size=e[now].size();
for(int i=0;i<size;i++)
if(visited[e[now][i].t]==false and e[now][i].w>0)
{
visited[e[now][i].t]=true;
dl[tail++]=e[now][i].t;
depth[e[now][i].t]=depth[now]+1;
}
head++;
}
return visited[1000];
}
int dfs(int now,int f)
{
if(now==1000)
return f;
int size=e[now].size(),ans=0;
for(int i=0;i<size;i++)
if(depth[e[now][i].t]==depth[now]+1 and e[now][i].w>0)
{
int t_ans=dfs(e[now][i].t,min(f,e[now][i].w));
e[now][i].w-=t_ans;
e[e[now][i].t][e[now][i].rev].w+=t_ans;
f-=t_ans,ans+=t_ans;
if(f==0) break;
}
return ans;
}
int Dinic()
{
int ans=0;
while(bfs())
ans+=dfs(1,inf);
return ans;
}
int main()
{
n=read(),f=read(),d=read();
for(int i=1;i<=1000;i++)
e[i].reserve(16);
for(int i=1;i<=f;i++)
AddLine(1,1+i);
for(int i=1;i<=d;i++)
AddLine(1+f+2*n+i,1000);
for(int i=1;i<=n;i++)
{
int F=read(),D=read(),temp;
for(int j=1;j<=F;j++)
{
temp=read();
AddLine(1+temp,1+f+i);
}
for(int j=1;j<=D;j++)
{
temp=read();
AddLine(1+f+n+i,1+f+2*n+temp);
}
}
for(int i=1;i<=n;i++)
AddLine(1+f+i,1+f+n+i); printf("%d",Dinic());
return 0;
}
C++
后记
写的时候发现自己真的有点生疏了,这种比较靠记忆的算法还是久不久搞一下来恢复记忆为妙
网络流的时间复杂度真玄学
[Luogu P2891/POJ 3281/USACO07OPEN ]吃饭Dining的更多相关文章
- 「洛谷P2891」[USACO07OPEN]吃饭Dining 解题报告
P2891 [USACO07OPEN]吃饭Dining 题目描述 Cows are such finicky eaters. Each cow has a preference for certain ...
- P2891 [USACO07OPEN]吃饭Dining
漂亮小姐姐点击就送:https://www.luogu.org/problemnew/show/P2891 题目描述 Cows are such finicky eaters. Each cow ha ...
- P2891 [USACO07OPEN]吃饭Dining(最大流+拆点)
题目描述 Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she w ...
- P2891 [USACO07OPEN]吃饭Dining 最大流
\(\color{#0066ff}{ 题目描述 }\) 有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料.现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类 ...
- 洛谷P2891 [USACO07OPEN]吃饭Dining
题目描述 Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she w ...
- 洛谷 P2891 [USACO07OPEN]吃饭Dining
裸的最大流. #include <cstdio> #include <cstring> #include <queue> const int MAXN = 4e3 ...
- [USACO07OPEN]吃饭Dining
嘟嘟嘟 这应该是网络流入门题之一了,跟教辅的组成这道题很像. 把每一只牛看成书,然后对牛拆点,因为每一只牛只要一份,食物和饮料分别看成练习册和答案. #include<cstdio> #i ...
- bzoj1711[USACO07OPEN]吃饭Dining
题意 有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料.现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮 ...
- poj 3281 Dining 网络流-最大流-建图的题
题意很简单:JOHN是一个农场主养了一些奶牛,神奇的是这些个奶牛有不同的品味,只喜欢吃某些食物,喝某些饮料,傻傻的John做了很多食物和饮料,但她不知道可以最多喂饱多少牛,(喂饱当然是有吃有喝才会饱) ...
随机推荐
- Centos-显示目录或者目录下文件信息-ls
ls 显示指定目录信息或指定目录下文件和目录信息,后边不跟文件目录路径信息默认为当前工作目录 默认显示输出信息的总行数统计数 相关参数 -a 显示所有文件或子目录,包含隐藏文档 # linux中以 . ...
- 075 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 07 综合案例-数组移位-主方法功能4的实现
075 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 07 综合案例-数组移位-主方法功能4的实现 本文知识点:综合案例-数组移位-主方法功能4的实现 说明:因为 ...
- 058 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 05 案例:求数组元素的最大值
058 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 05 案例:求数组元素的最大值 本文知识点:求数组元素的最大值 案例:求数组元素的最大值 程序代码及其执行过程 ...
- 03 Comments in C Programming C编程中的注释
Comments 注释简介 Let's take a quick break from programming and talk about comments. Comments help progr ...
- P2590 树的统计
一道树剖的模板题 首先,由于本人比较懒,就把单点修改写成了区间修改,其实也没有有多大区别(关键是我不会写单点修改QAQ) 不得不说,树剖的码量比较大,调了一上午才勉强调完. 这道题要求我们支持 单点修 ...
- Go 接口类型
接口作用 Go语言中的接口是一种类型,类似于Python中的抽象基类. Go语言中使用接口来体现多态,是duck-type的一种体现. 如,只要一个东西会叫,会走,那么我们就可以将它定义为一个动物的接 ...
- NOIP提高组2016 D2T3 【愤怒的小鸟】
貌似还没有写过状压DP的题目,嗯,刚好今天考了,就拿出来写一写吧. 题目大意: 额,比较懒,这次就不写了... 思路分析: 先教大家一种判断题目是不是状压DP的方法吧. 很简单,那就是--看数据范围! ...
- JVM 第四篇:可视化 JVM 故障处理工具
本文内容过于硬核,建议有 Java 相关经验人士阅读. 1. 可视化工具 在 JDK 中为我们提供了大量的 JVM 故障处理工具,都在 JDK 的 bin 目录下: 这其中除了大量的命令行工具以外,还 ...
- CAD& CG 2020 胡事民教授—开源框架Jittor的创新与探索
题目:深度学习框架"计图"的创新与探索 报告人:胡事民 报告人简介:胡事民,清华大学计算机系教授,主要研究方向为计算机图形学.虚拟现实.智能信息处理和系统软件等. 报告简介:深度学 ...
- 52.Qt-Charts动态显示多条折线电压值(实现示波器效果)
Qt 5.7过后Qt添加了官方的Chart库,之前就用的比较习惯,这次把源码发出来,给入门的同学们参考参考. 效果如下所示: 1.chartsView.h如下所示: #ifndef VIEW_H #d ...