题目链接:https://vjudge.net/problem/POJ-3281

Dining
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 20017   Accepted: 8901

Description

Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.

Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not be able to stuff everybody, he wants to give a complete meal of both food and drink to as many cows as possible.

Farmer John has cooked F (1 ≤ F ≤ 100) types of foods and prepared D (1 ≤ D ≤ 100) types of drinks. Each of his N (1 ≤ N ≤ 100) cows has decided whether she is willing to eat a particular food or drink a particular drink. Farmer John must assign a food type and a drink type to each cow to maximize the number of cows who get both.

Each dish or drink can only be consumed by one cow (i.e., once food type 2 is assigned to a cow, no other cow can be assigned food type 2).

Input

Line 1: Three space-separated integers: NF, and D 
Lines 2..N+1: Each line i starts with a two integers Fi and Di, the number of dishes that cow i likes and the number of drinks that cow i likes. The next Fi integers denote the dishes that cow i will eat, and the Di integers following that denote the drinks that cow i will drink.

Output

Line 1: A single integer that is the maximum number of cows that can be fed both food and drink that conform to their wishes

Sample Input

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

Sample Output

3

Hint

One way to satisfy three cows is: 
Cow 1: no meal 
Cow 2: Food #2, Drink #2 
Cow 3: Food #1, Drink #1 
Cow 4: Food #3, Drink #3 
The pigeon-hole principle tells us we can do no better since there are only three kinds of food or drink. Other test data sets are more challenging, of course.

Source

题意:

有N头牛, F个食物, D个饮料。每头牛只吃或者喝自己喜欢的食物或饮料,问:怎样分配,使得尽量多的牛能够获得一个食物或一个饮料?

题解:

题目要求就是要食物、饮料与牛进行匹配,但是又不能用匹配算法,因为有两种匹配。因而可以利用网络流:食物放左边,牛放中间,饮料放右边,然后最左边加个超级源点,最右边加个超级汇点。意思就是要:先将食物与牛进行匹配,然后再用匹配后的牛与饮料进行匹配。

1.超级源点与食物相连,且边的容量为1,表明每种食物只提供一份。

2.将每头牛拆成两点,左边与食物相连,边的容量为1,表明最多只能提供一份食物。右边与饮料相连,边的容量为1,表明最多只能提供一份饮料。然后内部相连,边的容量为1, 表明有“1头牛”。

3.每个饮料与超级汇点相连,且边的容量为1,表明每种饮料只提供一份。

4.建图完毕,求最大流即可。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+;
const int MAXN = 5e2+; int maze[MAXN][MAXN];
int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
int flow[MAXN][MAXN]; int sap(int start, int end, int nodenum)
{
memset(cur, , sizeof(cur));
memset(dis, , sizeof(dis));
memset(gap, , sizeof(gap));
memset(flow, , sizeof(flow));
int u = pre[start] = start, maxflow = , aug = INF;
gap[] = nodenum; while(dis[start]<nodenum)
{
loop:
for(int v = cur[u]; v<nodenum; v++)
if(maze[u][v]-flow[u][v]> && dis[u] == dis[v]+)
{
aug = min(aug, maze[u][v]-flow[u][v]);
pre[v] = u;
u = cur[u] = v;
if(v==end)
{
maxflow += aug;
for(u = pre[u]; v!=start; v = u, u = pre[u])
{
flow[u][v] += aug;
flow[v][u] -= aug;
}
aug = INF;
}
goto loop;
} int mindis = nodenum-;
for(int v = ; v<nodenum; v++)
if(maze[u][v]-flow[u][v]> && mindis>dis[v])
{
cur[u] = v;
mindis = dis[v];
}
if((--gap[dis[u]])==) break;
gap[dis[u]=mindis+]++;
u = pre[u];
}
return maxflow;
} int main()
{
int N, F, D;
while(scanf("%d%d%d",&N,&F,&D)!=EOF)
{
memset(maze, , sizeof(maze));
for(int i = ; i<N; i++)
{
int f, d, v;
scanf("%d%d", &f,&d);
while(f--)
{
scanf("%d", &v);
v--;
maze[v][F+D+i] = ; //food --> cow
}
while(d--)
{
scanf("%d", &v);
v--;
maze[F+D+N+i][F+v] = ; //cow' --> drink
}
maze[F+D+i][F+D+N+i] = ; // cow --> cow'
} int start = F+D+*N, end = F+D+*N+;
for(int i = ; i<F; i++) maze[start][i] = ; //超级源点 --> food
for(int i = F; i<F+D; i++) maze[i][end] = ; //drink --> 超级汇点 int ans = sap(start, end, F+D+*N+);
printf("%d\n", ans);
}
}

没有cur优化的sap:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+;
const int MAXN = 5e2+; int maze[MAXN][MAXN];
int gap[MAXN], dis[MAXN], pre[MAXN];
int flow[MAXN][MAXN]; int sap(int start, int end, int nodenum)
{
memset(dis, , sizeof(dis));
memset(gap, , sizeof(gap));
memset(flow, , sizeof(flow));
int u = pre[start] = start, maxflow = , aug = INF;
gap[] = nodenum; while(dis[start]<nodenum)
{
loop:
for(int v = ; v<nodenum; v++)
if(maze[u][v]-flow[u][v]> && dis[u] == dis[v]+)
{
aug = min(aug, maze[u][v]-flow[u][v]);
pre[v] = u;
u = v;
if(v==end)
{
maxflow += aug;
for(u = pre[u]; v!=start; v = u, u = pre[u])
{
flow[u][v] += aug;
flow[v][u] -= aug;
}
aug = INF;
}
goto loop;
} int mindis = nodenum-;
for(int v = ; v<nodenum; v++)
if(maze[u][v]-flow[u][v]>)
mindis = min(mindis, dis[v]); if((--gap[dis[u]])==) break;
gap[dis[u]=mindis+]++;
u = pre[u];
}
return maxflow;
} int main()
{
int N, F, D;
while(scanf("%d%d%d",&N,&F,&D)!=EOF)
{
memset(maze, , sizeof(maze));
for(int i = ; i<N; i++)
{
int f, d, v;
scanf("%d%d", &f,&d);
while(f--)
{
scanf("%d", &v);
v--;
maze[v][F+D+i] = ; //food --> cow
}
while(d--)
{
scanf("%d", &v);
v--;
maze[F+D+N+i][F+v] = ; //cow' --> drink
}
maze[F+D+i][F+D+N+i] = ; // cow --> cow'
} int start = F+D+*N, end = F+D+*N+;
for(int i = ; i<F; i++) maze[start][i] = ; //超级源点 --> food
for(int i = F; i<F+D; i++) maze[i][end] = ; //drink --> 超级汇点 int ans = sap(start, end, F+D+*N+);
printf("%d\n", ans);
}
}

没有cur和gap优化的sap:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+;
const int MAXN = 5e2+; int maze[MAXN][MAXN];
int dis[MAXN], pre[MAXN];
int flow[MAXN][MAXN]; int sap(int start, int end, int nodenum)
{
memset(dis, , sizeof(dis));
memset(flow, , sizeof(flow));
int u = pre[start] = start, maxflow = , aug = INF; while(dis[start]<nodenum)
{
loop:
for(int v = ; v<nodenum; v++)
if(maze[u][v]-flow[u][v]> && dis[u] == dis[v]+)
{
aug = min(aug, maze[u][v]-flow[u][v]);
pre[v] = u;
u = v;
if(v==end)
{
maxflow += aug;
for(u = pre[u]; v!=start; v = u, u = pre[u])
{
flow[u][v] += aug;
flow[v][u] -= aug;
}
aug = INF;
}
goto loop;
} int mindis = nodenum-;
for(int v = ; v<nodenum; v++)
if(maze[u][v]-flow[u][v]>)
mindis = min(mindis, dis[v]); dis[u]=mindis+;
u = pre[u];
}
return maxflow;
} int main()
{
int N, F, D;
while(scanf("%d%d%d",&N,&F,&D)!=EOF)
{
memset(maze, , sizeof(maze));
for(int i = ; i<N; i++)
{
int f, d, v;
scanf("%d%d", &f,&d);
while(f--)
{
scanf("%d", &v);
v--;
maze[v][F+D+i] = ; //food --> cow
}
while(d--)
{
scanf("%d", &v);
v--;
maze[F+D+N+i][F+v] = ; //cow' --> drink
}
maze[F+D+i][F+D+N+i] = ; // cow --> cow'
} int start = F+D+*N, end = F+D+*N+;
for(int i = ; i<F; i++) maze[start][i] = ; //超级源点 --> food
for(int i = F; i<F+D; i++) maze[i][end] = ; //drink --> 超级汇点 int ans = sap(start, end, F+D+*N+);
printf("%d\n", ans);
}
}

POJ3281 Dining —— 最大流 + 拆点的更多相关文章

  1. [poj3281]Dining(最大流+拆点)

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

  2. POJ3281 Dining 最大流

    题意:有f种菜,d种饮品,每个牛有喜欢的一些菜和饮品,每种菜只能被选一次,饮品一样,问最多能使多少头牛享受自己喜欢的饮品和菜 分析:建边的时候,把牛拆成两个点,出和入 1,源点向每种菜流量为1 2,每 ...

  3. poj3281 Dining 最大流(奇妙的构图)

    我是按照图论500题的文档来刷题的,看了这题怎么也不觉得这是最大流的题目.这应该是题目做得太少的缘故. 什么是最大流问题?最大流有什么特点? 最大流的特点我觉得有一下几点: 1.只有一个起点.一个终点 ...

  4. POJ 3281 Dining(最大流+拆点)

    题目链接:http://poj.org/problem?id=3281 题目大意:农夫为他的 N (1 ≤ N ≤ 100) 牛准备了 F (1 ≤ F ≤ 100)种食物和 D (1 ≤ D ≤ 1 ...

  5. POJ3281:Dining(dinic+拆点)

    题目链接:http://poj.org/problem?id=3281 PS:刷够网络流了,先这样吧,之后再刷,慢慢补. 题意:有F种食物,D种饮料,N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一 ...

  6. POJ3281 Dining(拆点构图 + 最大流)

    题目链接 题意:有F种食物,D种饮料N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一份) 一种食物被一头牛吃了之后,其余牛就不能吃了第一行有N,F,D三个整数接着2-N+1行代表第i头牛,前面两个整 ...

  7. <每日一题>Day 9:POJ-3281.Dining(拆点 + 多源多汇+ 网络流 )

    Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 24945   Accepted: 10985 Descript ...

  8. poj 3498 March of the Penguins(最大流+拆点)

    题目大意:在南极生活着一些企鹅,这些企鹅站在一些冰块上,现在要让这些企鹅都跳到同一个冰块上.但是企鹅有最大的跳跃距离,每只企鹅从冰块上跳走时会给冰块造成损害,因此企鹅跳离每个冰块都有次数限制.找出企鹅 ...

  9. poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分, dinic, isap

    poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分 dinic /* * Author: yew1eb * Created Time: 2014年10月31日 星期五 ...

随机推荐

  1. PHP文件上传设置和处理(多文件)

    <!--upload.php文件内容--><?phpheader("Content-Type:text/html;charset=utf-8");/* //原来$ ...

  2. pyserial安装

    参考网址:pyserial.sourceforge.net/pyserial.html#installation Download the archive from http://pypi.pytho ...

  3. BZOJ1017魔兽地图DotR 樹形DP

    @(BZOJ)[樹形DP, 三維DP] Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA ...

  4. mysql 5.7版本目录无data文件夹的解决办法

    安装mysql 5.7+版本时,若发现因根目录下,缺少data文件夹的情况, ***请不要去拷贝其他版本的data文件夹!*** 因为此操作会出现很多潜在问题:比如我遇到的执行show variabl ...

  5. 4.JAVA语言基础部分—枚举与泛型

    枚举 //定义枚举 enum MyEnum{ ITEM_A, ITEM_B } public static void main(String[] args) { //values()获取所枚举项的集合 ...

  6. 【面试 struts2】【第三篇】struts2的问题

    1.struts2的工作流程 1>客户端浏览器发出HTTP请求. 2>根据web.xml配置,该请求被FilterDispatcher接收 3>根据struts.xml配置,找到需要 ...

  7. BIM

    BIM进入中国已经有十来个年头,随着对BIM概念的深入了解.当前国内BIM应用逐渐由三维模型的可视化应用升级为基于BIM模型的信息进行项目精细化动态管理. 传统粗放的项目管理方法是工程项目难以进行精细 ...

  8. BUPT复试专题—二进制数(2012)

    https://www.nowcoder.com/practice/103dd589fed14457a673c613d8de3841?tpId=67&tqId=29634&tPage= ...

  9. MySQL Community Server 5.6和MySQL Installer 5.6

    mysql community server是mysql社区版的数据库服务器.即数据库软件. mysql installer是mysql软件的安装管理器,能够通过installer来选择安装mysql ...

  10. JSP简明教程:汇总

    原创JSP教程,简洁明了,不含废话. JSP简明教程(一):JSP简单介绍 JSP简明教程(二):JSP基本的语法 JSP简明教程(三):JSP隐含对象 JSP简明教程(四):EL表达式语言.Java ...