题意:
。。。
思路:
因为food和drink要么同时要,要不都不要,则需要把它们串起来,牛放中间
对牛进行拆点以限制每头牛吃了一份food,和一份drink
const int inf = INT_MAX/2;
const int Maxn = 100000;
const int MaxV = 500;
struct Edge {
int to, cap, rev;
};
vector<Edge> G[MaxV+5];
int level[MaxV+5], iter[MaxV+5]; // 距离标号,当前边
// 在残量网络里面加边
void add_edge(int from, int to, int cap) {
G[from].push_back( (Edge){to, cap, G[to].size()} );
G[to].push_back( (Edge){from, 0, G[from].size()-1} );
}
// bfs 构建层次
void bfs(int s) {
memset(level, -1, sizeof(level));
level[s] = 0;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();q.pop();
int sz = G[u].size();
for (int i=0;i<sz;++i) {
Edge &e = G[u][i];
if (e.cap > 0 && level[e.to] < 0) {
level[e.to] = level[u] + 1;
q.push(e.to);
}
}
}
}
int dfs(int x, int t, int f) {
//cout << "go " << x << endl;
if (x == t || f == 0) return f;
int flow = 0, sz = G[x].size();
for (int &i = iter[x]; i<sz;++i) {
Edge &e = G[x][i];
if (e.cap > 0 && level[x] < level[e.to]) {
int d = dfs(e.to, t, min (f, e.cap));
if (d > 0) {
e.cap -= d;
G[e.to][e.rev].cap += d;
flow += d;
f -= d;
if (!f) break;
}
}
}
return flow;
}
int max_flow(int s, int t) {
int flow = 0;
for (;;) {
bfs (s);
if (level[t] < 0) return flow;
memset(iter, 0, sizeof(iter));
flow += dfs(s, t, inf);
}
return flow;
}
int N, F, D, tot;
// 牛i拆成i, i+N, food-i-i+N-drink
// food i: i+2*N, drink i: i+2*N+F
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
SPEED_UP
cin >> N >> F >> D;
tot = 2*N+F+D;
rep(i, 1, N) {
int x, y, z;
cin >> x >> y;
rep(j, 1, x) {
cin >> z;
add_edge(z+2*N, i, 1);
}
rep(j, 1, y) {
cin >> z;
add_edge(i+N, z+2*N+F, 1);
}
}
// 每头牛自身拆点
rep(i, 1, N) {
add_edge(i, i+N, 1);
}
// 超级源点0
rep(i, 1, F) add_edge(0, i+2*N, 1);
// 超级汇点tot+1
rep(i, 1, D) add_edge(i+2*N+F, tot+1, 1);
int _max = max_flow(0, tot+1);
cout << _max << endl;
return 0;
}