传送门: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的更多相关文章

  1. 「洛谷P2891」[USACO07OPEN]吃饭Dining 解题报告

    P2891 [USACO07OPEN]吃饭Dining 题目描述 Cows are such finicky eaters. Each cow has a preference for certain ...

  2. P2891 [USACO07OPEN]吃饭Dining

    漂亮小姐姐点击就送:https://www.luogu.org/problemnew/show/P2891 题目描述 Cows are such finicky eaters. Each cow ha ...

  3. P2891 [USACO07OPEN]吃饭Dining(最大流+拆点)

    题目描述 Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she w ...

  4. P2891 [USACO07OPEN]吃饭Dining 最大流

    \(\color{#0066ff}{ 题目描述 }\) 有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料.现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类 ...

  5. 洛谷P2891 [USACO07OPEN]吃饭Dining

    题目描述 Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she w ...

  6. 洛谷 P2891 [USACO07OPEN]吃饭Dining

    裸的最大流. #include <cstdio> #include <cstring> #include <queue> const int MAXN = 4e3 ...

  7. [USACO07OPEN]吃饭Dining

    嘟嘟嘟 这应该是网络流入门题之一了,跟教辅的组成这道题很像. 把每一只牛看成书,然后对牛拆点,因为每一只牛只要一份,食物和饮料分别看成练习册和答案. #include<cstdio> #i ...

  8. bzoj1711[USACO07OPEN]吃饭Dining

    题意 有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料.现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮 ...

  9. poj 3281 Dining 网络流-最大流-建图的题

    题意很简单:JOHN是一个农场主养了一些奶牛,神奇的是这些个奶牛有不同的品味,只喜欢吃某些食物,喝某些饮料,傻傻的John做了很多食物和饮料,但她不知道可以最多喂饱多少牛,(喂饱当然是有吃有喝才会饱) ...

随机推荐

  1. (转载)浏览器 user-agent 字符串的故事

    本文转载自:http://www.cnblogs.com/ifantastic/p/3481231.html. 如有侵权,请联系处理!   你是否好奇标识浏览器身份的User-Agent,为什么每个浏 ...

  2. Python练习题 042:Project Euler 014:最长的考拉兹序列

    本题来自 Project Euler 第14题:https://projecteuler.net/problem=14 ''' Project Euler: Problem 14: Longest C ...

  3. Layman 使用ffmpeg-php扩展库实现视频截图(默认图)

    这几天做项目,其中一个需求是用户上传视频文件到服务器,然后服务器自动截取该视频的一帧作为该视频对应的缩略图,服务器端语言采用php编写,找了半天资料,发现ffmpeg-php可以满足该需求,所以下面简 ...

  4. java安全编码指南之:方法编写指南

    目录 简介 不要在构造函数中调用可以被重写的方法 不要在clone()方法中调用可重写的方法 重写equals()方法 hashCode和equals compareTo方法的实现 简介 java程序 ...

  5. 025 01 Android 零基础入门 01 Java基础语法 03 Java运算符 05 if条件结构

    025 01 Android 零基础入门 01 Java基础语法 03 Java运算符 05 if条件结构 本文知识点:Java中的if条件结构语句 关系运算符回顾 生活中根据条件进行判断采取不同操作 ...

  6. P1879 [USACO06NOV] Corn Fields G

    题目描述 农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地.John打算在牧场上的某几格里种上美味的草,供他 ...

  7. K-DTree入门

    \(K-D Tree\),一种用来维护\(K\)维数据的数据结构.常用于维护各种高维的数据,或者是邻近搜索等.从另一种意义上说,实际上就是高维的二叉搜索树.对于一些常见的问题,如\(k\)远点对.三位 ...

  8. 简说Modbus-RTU与Modbus-ASCII

    Modbus在串行总线通信中的协议有RTU和ASCII两种.RTU是Remote Terminal Unit的缩写,意思是远程终端单元.ASCII是American Standard Code for ...

  9. ansible-介绍

    常用自动化运维工具 CFengine Chef Puppet 基于Ruby开发,采用C/S架构,扩展性强,基于SSL认证 SaltStack 基于python开发,采用C/S架构,相对于puppet更 ...

  10. Go 并发操作

    goroutine 在其他的编程语言中,线程调度是交由os来进行处理的. 但是在Go语言中,会对此做一层封装,Go语言中的并发由goroutine来实现,它类似于用户态的线程,更类似于其他语言中的协程 ...