您的位置:首页 > 其它

POJ-3281 Dining (最大流[Ford-Fulkerson])

2016-05-14 00:05 309 查看
Dining
http://poj.org/problem?id=3281

Time Limit: 2000MSMemory Limit: 65536K
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: N, F, 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 theDi 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.

题目大意:总共有n头牛,f类食物,d类饮料,每头牛愿意吃一些种类的食物和饮料,每种食物和饮料只能用一次,求最多能使几头牛能吃到食物并且喝到饮料?

首先,一头牛必须吃到一种食物,喝到一种饮料才算数,所以食物和饮料同时连到一头牛身上是不可以的(可以看做并联吧),然后就想到拆点,但是拆点后怎么连都还是是并联,完全没想到换一下顺序...最终还是看了一下思路:牛拆成两个点牛1和牛2,牛1到牛2有权值为1的边(保证一头牛只计入一次),源点到食物有权值为1的边(保证一种食物只用一次),食物到牛1有权值为1的边,牛2到饮料有权值为1的边,饮料到汇点有权值为1的边(保证一种饮料只用一次)

然后就可以开心的跑最大流了

数组队列开小了,又返回WA,还倔强地不相信会错这,实在找不到改了一下就AC

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int STA=0;
const int DES=1;

struct Node {
int pre,u,mn;
}q[250005],cur;

int n,f,d,fn,dn,fi,di,fsta,dsta;
int g[505][505],pre[505],head,tail;
bool vis[505];

int bfs(int sta,int des) {
memset(vis,false,sizeof(vis));
head=tail=0;
q[tail].pre=-1;
q[tail].u=sta;
q[tail++].mn=0x3f3f3f3f;

while(head!=tail) {
do {
cur=q[head++];
} while(head!=tail&&vis[cur.u]);
if(vis[cur.u]) {
return 0;
}

pre[cur.u]=cur.pre;
vis[cur.u]=true;
if(cur.u==des) {
return cur.mn;
}
for(int i=0;i<n;++i) {
if(!vis[i]&&g[cur.u][i]!=0) {
q[tail].pre=cur.u;
q[tail].u=i;
q[tail++].mn=min(cur.mn,g[cur.u][i]);
}
}
}
return 0;
}

int Ford_Fulkerson(int sta,int des) {
int ans=0,e,mn;
while(mn=bfs(sta,des),mn!=0) {
ans+=mn;
e=des;
while(e!=sta) {
g[pre[e]][e]-=mn;
g[e][pre[e]]+=mn;
e=pre[e];
}
}
return ans;
}

int main() {
while(3==scanf("%d%d%d",&n,&f,&d)) {
memset(g,0,sizeof(g));
fsta=(n+1)<<1;//食物点的起始下标
dsta=fsta+f;//饮料点的起始下标
for(int i=0;i<f;++i) {
g[STA][fsta+i]=1;//源点到每个食物均有一条权值为1的边,表示该食物只能用一次
}
for(int i=0;i<d;++i) {
g[dsta+i][DES]=1;//每个饮料到汇点均有一条权值为1的边,表示该饮料只能用一次
}

for(int i=1;i<=n;++i) {
g[i<<1][(i<<1)|1]=1;//一头牛拆成两个点,其本身边权值为1,以限制一头牛只能用一次
scanf("%d%d",&fn,&dn);
while(fn-->0) {
scanf("%d",&fi);
g[fsta+fi-1][i<<1]=1;//前面的点由食物点到达
}
while(dn-->0) {
scanf("%d",&di);
g[(i<<1)|1][dsta+di-1]=1;//后面的点到达饮料
}
}
n=dsta+d;
printf("%d\n",Ford_Fulkerson(STA,DES));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: