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日 星期五 ...
随机推荐
- LVM 类型的 Storage Pool
LVM 类型的 Storage Pool 不仅一个文件可以分配给客户机作为虚拟磁盘,宿主机上 VG 中的 LV 也可以作为虚拟磁盘分配给虚拟机使用. 不过,LV 由于没有磁盘的 MBR 引导记录,不能 ...
- 系统进程的Watchdog
编写者:李文栋 /rayleeya http://rayleeya.iteye.com/blog/1963408 3.1 Watchdog简介 对于像笔者这样没玩过硬件的纯软程序员来说,第一次看到这个 ...
- asp.net开发的调试方法集合
调试是写代码一共非常重要的步骤,掌握好调试的技巧对于编程有事半功倍的效果,下面是我总结的菜鸟用方法 1.关于HTML和JS的调试 JS曾经是我最讨厌的错误,因为大多数错误VS不报错,这是因为js是解释 ...
- POJ 3694 (tarjan缩点+LCA+并查集)
好久没写过这么长的代码了,题解东哥讲了那么多,并查集优化还是很厉害的,赶快做做前几天碰到的相似的题. #include <iostream> #include <algorithm& ...
- Neo4j 第七篇:模式(Pattern)
模式和模式匹配是Cypher的核心,使用模式来描述所需数据的形状,该模式使用属性图的结构来描述,通常使用小括号()表示节点,-->表示关系,-[]->表示关系和关系的类型,箭头表示关系的方 ...
- Hadoop安装和基本单机部署
下载安装 # 下载 $ cd /usr/local $ wget http://mirrors.hust.edu.cn/apache/hadoop/common/hadoop-2.9.2/hadoo ...
- 关于时间,日期,星期,月份的算法(Java中Calendar的使用方法)
原文:http://www.open-open.com/code/view/1446195787257 package cn.outofmemory.codes.Date; import java.u ...
- reason: '*** setObjectForKey: object cannot be nil (key: 1)'-crash!
[self.imageDownloadsInProgress setObject:iconDownloader forKey:[NSNumber numberWithInteger:tag]]; 字典 ...
- IT部门的KPI该如何制定?
导语:信息化成本.系统开机率.网路不断线时数.系统运行速度.软件开发时间.用户问题处理反应时间.系统品质.用户满意度--哪些指标是可被管理的,能指引IT部门成为一个有价值的.为企业带来效益的部门呢? ...
- How to Install a Language Pack
https://www.phpbb.com/kb/article/how-to-install-a-language-pack