POJ3281 Dining —— 最大流 + 拆点
题目链接:https://vjudge.net/problem/POJ-3281
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
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
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
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 —— 最大流 + 拆点的更多相关文章
- [poj3281]Dining(最大流+拆点)
题目大意:有$n$头牛,$f$种食物和$d$种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料.每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢 ...
- POJ3281 Dining 最大流
题意:有f种菜,d种饮品,每个牛有喜欢的一些菜和饮品,每种菜只能被选一次,饮品一样,问最多能使多少头牛享受自己喜欢的饮品和菜 分析:建边的时候,把牛拆成两个点,出和入 1,源点向每种菜流量为1 2,每 ...
- poj3281 Dining 最大流(奇妙的构图)
我是按照图论500题的文档来刷题的,看了这题怎么也不觉得这是最大流的题目.这应该是题目做得太少的缘故. 什么是最大流问题?最大流有什么特点? 最大流的特点我觉得有一下几点: 1.只有一个起点.一个终点 ...
- POJ 3281 Dining(最大流+拆点)
题目链接:http://poj.org/problem?id=3281 题目大意:农夫为他的 N (1 ≤ N ≤ 100) 牛准备了 F (1 ≤ F ≤ 100)种食物和 D (1 ≤ D ≤ 1 ...
- POJ3281:Dining(dinic+拆点)
题目链接:http://poj.org/problem?id=3281 PS:刷够网络流了,先这样吧,之后再刷,慢慢补. 题意:有F种食物,D种饮料,N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一 ...
- POJ3281 Dining(拆点构图 + 最大流)
题目链接 题意:有F种食物,D种饮料N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一份) 一种食物被一头牛吃了之后,其余牛就不能吃了第一行有N,F,D三个整数接着2-N+1行代表第i头牛,前面两个整 ...
- <每日一题>Day 9:POJ-3281.Dining(拆点 + 多源多汇+ 网络流 )
Dining Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 24945 Accepted: 10985 Descript ...
- poj 3498 March of the Penguins(最大流+拆点)
题目大意:在南极生活着一些企鹅,这些企鹅站在一些冰块上,现在要让这些企鹅都跳到同一个冰块上.但是企鹅有最大的跳跃距离,每只企鹅从冰块上跳走时会给冰块造成损害,因此企鹅跳离每个冰块都有次数限制.找出企鹅 ...
- poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分, dinic, isap
poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分 dinic /* * Author: yew1eb * Created Time: 2014年10月31日 星期五 ...
随机推荐
- Spring JdbcTemplate 查询方法中的RowMapper实现汇总
实现一.在内部建立内联类实现RowMapper接口 package hysteria.contact.dao.impl; import java.sql.ResultSet; import java. ...
- Java线程池快速学习教程
1. Java线程池 线程池:顾名思义,用一个池子装载多个线程,使用池子去管理多个线程. 问题来源:应用大量通过new Thread()方法创建执行时间短的线程,较大的消耗系统资源并且系统的响应速度变 ...
- DP的序--Codeforces956E. Wardrobe
$n \leq 10000$个盒子,有高度,高度总和$\leq 10000$,盒子有重要的和不重要的,问最多有多少重要盒子的底端在区间$[L,R]$. 这是个入门级的DP,但需要一点胆量MD这题能放D ...
- 487. Max Consecutive Ones II
Given a binary array, find the maximum number of consecutive 1s in this array if you can flip at mos ...
- Jenkins中的Job配置里缺少“触发远程构建(例如,使用脚本)”选项的问题解决
如图所示的功能没有出现在Job配置页面,这是由于权限问题导致的,解决方法如下: 1.[系统管理]->[Configure Global Security] 2.配置如下: 3.或者你有第三方权限 ...
- 【java】java 中 byte[]、File、InputStream 互相转换
========================================================================= 使用过程中,一定要注意close()掉各个读写流!! ...
- Python爬虫简单实现之Q乐园图片下载
根据需求写代码实现.然而跟我并没有什么关系,我只是打开电脑望着屏幕想着去干点什么,于是有了这个所谓的“需求”. 终于,我发现了Q乐园——到底是我老了还是我小了,这是什么神奇的网站,没听过啊,就是下面酱 ...
- 杭电1863 畅通project
畅通project Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 【转】Linux cp -a用法
cp file1 file1-bk ---------> 这样复制备份的话文件的属性(创建时间这些会变化) 要想不变化, cp -a file1 file-bk 加上一个 -a 这个参数就 ...
- 把握linux内核设计思想(十二):内存管理之slab分配器
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流.请勿用于商业用途] 上一节最后说到对于小内存区的请求,假设採用伙伴系统来进行分配,则会在页内产生非 ...