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} 中选
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总食品和饮料).当然,别的数据会更难.
输出解释:
一个方案是:
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 ", ans); return 0; }