BZOJ 1711: [Usaco2007 Open]Dining吃饭

时间:2023-03-08 18:50:34

1711: [Usaco2007 Open]Dining吃饭

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 902  Solved: 476
[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总食品和饮料).当然,别的数据会更难.

HINT

Source

[Submit][Status][Discuss]

网络流,拆点建图,每一条流都对应着满足一头牛的方案。和今天考试T1贼像……

 #include <cstdio>

 inline int nextChar(void) {
const int siz = ; static char buf[siz];
static char *hd = buf + siz;
static char *tl = buf + siz; if (hd == tl)
fread(hd = buf, , siz, stdin); return *hd++;
} inline int nextInt(void) {
register int ret = ;
register int neg = false;
register int bit = nextChar(); for (; bit < ; bit = nextChar())
if (bit == '-')neg ^= true; for (; bit > ; bit = nextChar())
ret = ret * + bit - ; return neg ? -ret : ret;
} inline int min(int a, int b)
{
return a < b ? a : b;
} const int siz = ;
const int inf = ; int tot;
int s, t;
int hd[siz];
int to[siz];
int fl[siz];
int nt[siz]; inline void add(int u, int v, int f)
{
nt[tot] = hd[u]; to[tot] = v; fl[tot] = f; hd[u] = tot++;
nt[tot] = hd[v]; to[tot] = u; fl[tot] = ; hd[v] = tot++;
} int dep[siz]; inline bool bfs(void)
{
static int que[siz], head, tail; for (int i = s; i <= t; ++i)dep[i] = ; dep[que[head = ] = s] = tail = ; while (head != tail)
{
int u = que[head++], v; for (int i = hd[u]; ~i; i = nt[i])
if (!dep[v = to[i]] && fl[i])
dep[que[tail++] = v] = dep[u] + ;
} return dep[t];
} int cur[siz]; int dfs(int u, int f)
{
if (u == t || !f)
return f; int used = , flow, v; for (int i = cur[u]; ~i; i = nt[i])
if (dep[v = to[i]] == dep[u] + && fl[i])
{
flow = dfs(v, min(fl[i], f - used)); used += flow;
fl[i] -= flow;
fl[i^] += flow; if (used == f)
return f; if (fl[i])
cur[u] = i;
} if (!used)
dep[u] = ; return used;
} inline int maxFlow(void)
{
int maxFlow = , newFlow; while (bfs())
{
for (int i = s; i <= t; ++i)
cur[i] = hd[i]; while (newFlow = dfs(s, inf))
maxFlow += newFlow;
} return maxFlow;
} int N, F, D; inline int cow(int x, int y)
{
return F + D + y * N + x;
} inline int food(int x)
{
return x;
} inline int drink(int x)
{
return x + F;
} signed main(void)
{
N = nextInt();
F = nextInt();
D = nextInt(); s = , t = N* + F + D + ; for (int i = s; i <= t; ++i)
hd[i] = -; for (int i = ; i <= F; ++i)
add(s, food(i), ); for (int i = ; i <= D; ++i)
add(drink(i), t, ); for (int i = ; i <= N; ++i)
{
int f = nextInt();
int d = nextInt(); add(cow(i, ), cow(i, ), ); for (int j = ; j <= f; ++j)
add(food(nextInt()), cow(i, ), ); for (int j = ; j <= d; ++j)
add(cow(i, ), drink(nextInt()), );
} printf("%d\n", maxFlow());
}

@Author: YouSiki