[BZOJ1711][Usaco2007 Open]Dining吃饭

Posted Elder_Giang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1711][Usaco2007 Open]Dining吃饭相关的知识,希望对你有一定的参考价值。

1711: [Usaco2007 Open]Dining吃饭

Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1057  Solved: 569 [Submit][Status][Discuss]

Description

农夫JOHN为牛们做了很好的食品,但是牛吃饭很挑食. 每一头牛只喜欢吃一些食品和饮料而别的一概不吃.虽然他不一定能把所有牛喂饱,他还是想让尽可能多的牛吃到他们喜欢的食品和饮料. 农夫JOHN做了F (1 <= F <= 100) 种食品并准备了D (1 <= D <= 100) 种饮料. 他的N (1 <= N <= 100)头牛都以决定了是否愿意吃某种食物和喝某种饮料. 农夫JOHN想给每一头牛一种食品和一种饮料,使得尽可能多的牛得到喜欢的食物和饮料. 每一件食物和饮料只能由一头牛来用. 例如如果食物2被一头牛吃掉了,没有别的牛能吃食物2.

Input

* 第一行: 三个数: N, F, 和 D

* 第2..N+1行: 每一行由两个数开始F_i 和 D_i, 分别是第i 头牛可以吃的食品数和可以喝的饮料数.下F_i个整数是第i头牛可以吃的食品号,再下面的D_i个整数是第i头牛可以喝的饮料号码.

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

输入解释:

牛 1:  食品从 {1,2}, 饮料从 {1,2} 中选
牛 2:  食品从 {2,3}, 饮料从 {1,2} 中选
牛 3:  食品从 {1,3}, 饮料从 {1,2} 中选
牛 4:  食品从 {1,3}, 饮料从 {3} 中选

Sample Output

3
输出解释:

一个方案是:
Cow 1: 不吃
Cow 2: 食品 #2, 饮料 #2
Cow 3: 食品 #1, 饮料 #1
Cow 4: 食品 #3, 饮料 #3
用鸽笼定理可以推出没有更好的解 (一共只有3总食品和饮料).当然,别的数据会更难.
 
最大流(传说中的三分匹配??)
#include <cstdio>
#include <algorithm>
using namespace std;
struct Edge{
    int to, cap, next;
    Edge(){}
    Edge(int _t, int _w, int _n): to(_t), cap(_w), next(_n){}
}e[50000];
int fir[410] = {0}, cur[410], cnt = 1;
inline void ins(int u, int v, int w){
    e[++cnt] = Edge(v, w, fir[u]); fir[u] = cnt;
    e[++cnt] = Edge(u, 0, fir[v]); fir[v] = cnt;
}
int sour, sink;
int lev[410], vis[410], bfn = 0;
int q[410], h, t;
inline bool bfs(){
    h = t = 0;
    q[t++] = sour;
    vis[sour] = ++bfn;
    lev[sour] = 1;
    while(h != t){
        for(int i = fir[q[h]]; i; i = e[i].next){
            if(!e[i].cap || vis[e[i].to] == bfn) continue;
            vis[e[i].to] = bfn;
            lev[e[i].to] = lev[q[h]] + 1;
            q[t++] = e[i].to;
        }
        h++;
    }
    return vis[sink] == bfn;
}
int dfs(int now, int flow){
    if(now == sink) return flow;
    int t, ret = 0;
    for(int &i = cur[now]; i; i = e[i].next){
        if(!e[i].cap || lev[e[i].to] != lev[now] + 1) continue;
        t = dfs(e[i].to, min(flow, e[i].cap));
        ret += t;
        flow -= t;
        e[i].cap -= t;
        e[i ^ 1].cap += t;
        if(!flow) break;
    }
    if(!ret) lev[now] = 0;
    return ret;
}
int N, F, D;
int main(){
    scanf("%d %d %d", &N, &F, &D);
    sour = 0;
    sink = N * 2 + F + D + 1;
    for(int i = 1; i <= N; i++) ins(i, i + N, 1);
    for(int i = 1; i <= F; i++) ins(sour, i + 2 * N, 1);
    for(int i = 1; i <= D; i++) ins(i + F + 2 * N, sink, 1);
    for(int f, d, t, i = 1; i <= N; i++){
        scanf("%d %d", &f, &d);
        for(int j = 1; j <= f; j++){
            scanf("%d", &t);
            ins(t + 2 * N, i, 1);
        }
        for(int j = 1; j <= d; j++){
            scanf("%d", &t);
            ins(i + N, t + 2 * N + F, 1);
        }
    }
    int ans = 0;
    while(bfs()){
        for(int i = sour; i <= sink; i++) cur[i] = fir[i];
        ans += dfs(sour, 1 << 30);
    }
    printf("%d\n", ans);
    return 0;
}

 

以上是关于[BZOJ1711][Usaco2007 Open]Dining吃饭的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1711 [Usaco2007 Open]Dining吃饭

bzoj 1711: [Usaco2007 Open]Dining吃饭

BZOJ1711: [Usaco2007 Open]Dining吃饭

bzoj1711: [Usaco2007 Open]Dining吃饭

BZOJ 1711:[Usaco2007 Open]Dining吃饭(最大流)

最大流bzoj1711: [Usaco2007 Open]Dining吃饭