设容量为1,流量为0的边为edge.
用0表示源点,从零到每个食物之间连上edge,在从食物到相应的牛上连上edge,再从第i个牛到第i个牛上连上edge,在从牛到饮料上连上edge,从饮料到汇点连上edge.
食物标记:1-f;
第一次n头牛f+1, f+n;
第二次n头牛f+n+1, f+2*n;
饮料:f+2*n+1, f+2*n+d;
汇点:f+2*n+d+1;
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#define maxn 605
#define INF 1e9
typedef long long ll;
using namespace std;
struct Edge{
Edge(){
}
Edge(int a, int b, int c, int d){
from = a;
to = b;
cap = c;
flow = d;
}
int from, to, cap, flow;
};
vector<Edge> edge;
vector<int> v[maxn];
int p[maxn], a[maxn], n, f, d;
void Addedge(int from, int to){
edge.push_back(Edge(from, to, 1, 0));
edge.push_back(Edge(to, from, 0, 0));
int dd = edge.size();
v[from].push_back(dd-2);
v[to].push_back(dd-1);
}
void Init(){
edge.clear();
for(int i = 0; i < maxn; i++)
v[i].clear();
for(int i = 1; i <= n; i++){
int k1, k2, a;
scanf("%d%d", &k1, &k2);
for(int j = 1; j <= k1; j++){
scanf("%d", &a);
Addedge(a, i+f);
}
for(int j = 1; j <= k2; j++){
scanf("%d", &a);
Addedge(f+n+i, f+2*n+a);
}
}
for(int i = 1; i <= f; i++){
Addedge(0, i);
}
for(int i = 1; i <= d; i++){
Addedge(f+2*n+i, f+2*n+d+1);
}
for(int i = 1; i <= n; i++){
Addedge(i+f, i+f+n);
}
}
int MaxFlow(){
int e = f + 2 * n + d + 1;
int ans = 0;
while(1){
memset(a, 0, sizeof(a));
a[0] = INF;
queue<int> q;
q.push(0);
while(!q.empty()){
int k = q.front();
q.pop();
for(int i = 0; i < v[k].size(); i++){
Edge &e = edge[v[k][i]];
if(a[e.to] == 0 && e.cap > e.flow){
a[e.to] = min(a[k], e.cap - e.flow);
q.push(e.to);
p[e.to] = v[k][i];
}
}
}
if(a[e] == 0)
break;
ans += a[e];
for(int i = e; i != 0; i = edge[p[i]].from){
edge[p[i]].flow += 1;
edge[p[i]^1].flow -= 1;
}
}
return ans;
}
int main(){
// freopen("in.txt", "r", stdin);
while(scanf("%d%d%d",&n, &f, &d) == 3){
Init();
cout << MaxFlow() << endl;
}
return 0;
}