就是比二分图匹配多一个, 把牛放中间, 食物和饮料放两边, 然后就是用一个牛拷贝一份, 这样防止多分牛奶或者食物流到同一只牛的地方, 然后每一条边的权值是1
//SPA
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define CLR(arr, val) memset(arr, val, sizeof(arr))
#pragma warning(disable:4996)
using namespace std;
const int MaxV = 10000;
const int MaxE = 10000 << 1;
const int INF = 1e9;
struct Graph
{
struct Vertex
{
int head;
}V[MaxV];
struct Edge
{
int v, c, f, next;
Edge(){}
Edge(int v,int c, int f, int next):v(v), c(c), f(f), next(next){}
}E[MaxE];
void init()
{
top = 0;
CLR(V, -1);
}
void addEdge(int u, int v,int w)
{
E[top] = Edge(v, w, 0, V[u].head);
V[u].head = top++;
E[top] = Edge(u, 0, 0, V[v].head);
V[v].head = top++;
}
int top;
};
int h[MaxV]; //高度
int path[MaxV]; //回路
int gap[MaxV]; //gap优化
int cur[MaxV]; //当前弧优化
int s, t;
int vexNum, edgeNum;
Graph g;
void setHeight()
{
CLR(gap, 0);
CLR(h, -1);
h[t] = 0;
queue<int>Q;
Q.push(t);
while(!Q.empty())
{
int top = Q.front();
gap[ h[top] ]++;
for(int i = g.V[top].head; i != -1; i = g.E[i].next)
{
int v = g.E[i].v;
if(h[v] == -1)
{
h[v] = h[top] + 1;
Q.push(v);
}
}
Q.pop();
}
}
int sap()
{
setHeight();
int maxFlow = 0, u = s;
int flow = INF;
for(int i = 0; i <= vexNum; i++)
cur[i] = g.V[i].head;
while(h[s] < vexNum)
{
int &i = cur[u];
for(; i != -1; i = g.E[i].next)
{
int v = g.E[i].v;
if(g.E[i].c > g.E[i].f && h[u] == h[v] + 1)
{
u = v;
path[v] = i;
flow = min(flow, g.E[i].c - g.E[i].f);
if(u == t)
{
while(u != s)
{
int j = path[u];
g.E[j].f += flow;
g.E[j ^ 1].f -= flow;
u = g.E[j ^ 1].v;
}
maxFlow += flow;
flow = INF;
}
break;
}
}
if(i == -1)
{
if(--gap[ h[u] ] == 0)
break;
int minH = vexNum - 1;
cur[u] = g.V[u].head;
for(int j = g.V[u].head; j != -1; j = g.E[j].next)
if(g.E[j].c > g.E[j].f)
minH = min(minH, h[g.E[j].v]);
h[u] = minH + 1;
++gap[ h[u] ];
if(u != s)
u = g.E[path[u] ^ 1].v;
}
}
return maxFlow;
}
int N, F, D;
void buildMap()
{
for(int i = 1; i <= F; i++)
g.addEdge(0, i, 1);
for(int i = F + 1; i <= F + N; i++)
g.addEdge(i, i + N, 1);
for(int i = F + N * 2 + 1; i <= F + N * 2 + D; i++)
g.addEdge(i, vexNum, 1);
int f, d;
for(int i = 1; i <= N; i++) //n头牛
{
scanf("%d %d", &f, &d);
while(f--)
{
int v;
scanf("%d", &v);
g.addEdge(v, F + i, 1);
}
while(d--)
{
int v;
scanf("%d", &v);
g.addEdge(F + N + i, F + 2* N + v, 1);
}
}
}
int main()
{
while(scanf("%d %d %d", &N, &F, &D) != EOF)
{
g.init();
vexNum = F + 2 * N + D + 1;
buildMap();
s = 0, t = vexNum;
printf("%d\n", sap());
}
return 0;
}