题目链接: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. Virtual Box 安装过程(卸载Vmware后)

    VirtualBox安装前的操作:(或许某些操作不一定有用,但是我是这么做下来的,最后也安装成功了) 步骤一:停止之前安装的vmware的所有服务(如果之前没有安装过虚拟机软件,无需做此操作)VMwa ...

  2. git提交之后没有push,代码被覆盖之后恢复

    git  reflog  通过这个看commit id git reset [commit id] --hard   有时候要删除一个index.lock文件.

  3. uva 11235 RMQ范围最大值

    题目大意:给一个整数上升序列,对于一系列询问区间(i,j),回答这段区间出现次数最多值所出现的次数. 分析:一个上升序列,相同的值聚集在一起,把相同的值的区间看作一个整体,假设这样的整体有n个,把他们 ...

  4. COdevs 2823 锁妖塔

    2823 锁妖塔 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 琐妖塔会在一会儿后倒塌.大量妖魔涌出塔去,塔内的楼梯都挤满了人(哦 ...

  5. localStorage增删改查

    /** * 设置 本地缓存 */ export function setStorage(key, obj) { if (typeof obj === 'string') { localStorage. ...

  6. 转 DOS 8.3 文件名命名规则

    http://www.360doc.com/content/10/0813/14/73007_45757514.shtml DOS 8.3 文件名命名规则 经常看到命令行或者其它软件在显示目录的时候出 ...

  7. python--输出自己需要的字符串连接的的方式

    python中有很多字符串连接方式,今天在写代码,顺便总结一下,从最原始的字符串连接方式到字符串列表连接,大家感受下: 最原始的字符串连接方式:str1 + str2 python 新字符串连接语法: ...

  8. AC日记——A+B Problem(再升级) 洛谷 P1832

    题目背景 ·题目名称是吸引你点进来的 ·实际上该题还是很水的 题目描述 ·1+1=? 显然是2 ·a+b=? 1001回看不谢 ·哥德巴赫猜想 似乎已呈泛滥趋势 ·以上纯属个人吐槽 ·给定一个正整数n ...

  9. 关于几种UI框架简单总结

    最近两年多的时间先后做过几款终端程序,UI框架从MFC转向过WxWidgets,之后再转向Qt.三种框架精通远谈不上,用起来还是没什么问题. 简单聊聊三种框架的优缺点. 1.MFC 似乎作为一种饱受批 ...

  10. 深入GCD(五):资源竞争

    概述我将分四步来带大家研究研究程序的并发计算.第一步是基本的串行程序,然后使用GCD把它并行计算化.如果你想顺着步骤来尝试这些程序的话,可以下载源码.注意,别运行imagegcd2.m,这是个反面教材 ...