题意
有N头牛,F种吃的,D种喝的。每头牛都有自己钟意的多种食物和饮料。但是每样只能选一个。每种食物和饮料对外只提供一次。比如A,B都喜欢C这
种食物,如果A要了,B就不能再选用。问最多有多少头牛可以同时享用自己钟意的食物和饮料。
分析
建立超级源点s和汇点t。然后将牛拆点,放在中间
如:s->F[i]->N[k]->N[k + N]->D[j]->t
这样建立图,每条边的容量为1即可,然后就是最大流。
Dinic版本
const int maxn = 500;
const int maxm = 41000;
int n,f,d;
int s, t;
int cap[maxm], nxt[maxm], flow[maxm], head[maxn], pnt[maxm];
int ecnt;
inline void Addedge(int u,int v,int c) {
pnt[ecnt] = v, cap[ecnt] = c, nxt[ecnt] = head[u], flow[ecnt] = 0, head[u] = ecnt++;
pnt[ecnt] = u, cap[ecnt] = 0, nxt[ecnt] = head[v], flow[ecnt] = 0, head[v] = ecnt++;
}
inline void Input() {
memset(head, -1,sizeof head);
ecnt = 0;
int a,b,x;
for (int i = 1;i <= n;++i) {
Addedge(f+d+i,f+d+n+i,1);
scanf("%d%d",&a,&b);
for (int j = 1;j <= a;++j) {
scanf("%d",&x);
Addedge(x, f+d+i, 1);
}
for (int j = 1;j <= b;++j) {
scanf("%d",&x);
Addedge(f+d+n+i, f+x, 1);
}
}
s = 0, t = 2*n+f+d+1;
for (int i = 1;i <= f;++i)
Addedge(s, i, 1);
for (int i = 1;i <= d;++i)
Addedge(f+i, t, 1);
}
int dis[maxn];
bool spfa() {
queue<int> que;
memset(dis, -1,sizeof dis);
que.push(s);
dis[s] = 0;
while(!que.empty()) {
int u = que.front();
que.pop();
for (int i = head[u];i != -1;i = nxt[i]) {
int v = pnt[i];
if (cap[i] > flow[i] && dis[v] == -1) {
dis[v] = dis[u] + 1;
que.push(v);
}
}
}
return dis[t] != -1;
}
int dfs(int u,int a) {
if (u == t || a == 0) return a;
int ret = 0, f;
for (int i = head[u];i != -1;i = nxt[i]) {
int v = pnt[i];
if (dis[v] > dis[u] && (f = dfs(v, min(a, cap[i] - flow[i]))) > 0) {
ret += f;
a -= f;
flow[i] += f;
flow[i^1] -= f;
if (a == 0) break;
}
}
return ret;
}
inline int dinic() {
int ret = 0;
while(spfa()) {
// cout << "here\n";
ret += dfs(s, INF);
}
return ret;
}
ISAP版本
const int maxn = 500;
struct Edge{
int from, to, cap, flow;
Edge(){}
Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
};
struct ISAP{
int p[maxn], num[maxn], cur[maxn], d[maxn];
int s, t, n, m;
bool vis[maxn];
vector<int> G[maxn];
vector<Edge> edges;
void init(int n) {
this->n = n;
for (int i = 0;i <= n;++i) {
G[i].clear();
d[i] = INF;
}
edges.clear();
}
void addedge(int from,int to,int cap) {
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = (int)edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
bool bfs() {
memset(vis, false,sizeof vis);
queue<int> que;
d[t] = 0;
vis[t] = true;
que.push(t);
while(!que.empty()) {
int u = que.front();
que.pop();
for (int i = 0;i < G[u].size();++i) {
Edge& e = edges[G[u][i]^1];
if (e.cap > e.flow && !vis[e.from]) {
vis[e.from] = true;
d[e.from] = d[u] + 1;
que.push(e.from);
}
}
}
return vis[s];
}
int Augment() {
int u = t, flow = INF;
while(u != s) {
Edge& e = edges[p[u]];
flow = min(flow, e.cap - e.flow);
u = edges[p[u]].from;
}
u = t;
while(u != s) {
edges[p[u]].flow += flow;
edges[p[u]^1].flow -= flow;
u = edges[p[u]].from;
}
return flow;
}
int MaxFlow(int s,int t) {
this->s = s,this->t = t;
int ret = 0;
bfs();
if (d[s] >= n) return 0;
memset(num, 0,sizeof num);
memset(cur, 0,sizeof cur);
for (int i = 0;i < n;++i) {
if (d[i] < INF) num[d[i]]++;
}
int u = s;
while(d[s] < n) {
if (u == t) {
ret += Augment();
u = s;
}
bool ok = false;
for (int i = cur[u];i < G[u].size();++i) {
Edge& e = edges[G[u][i]];
if (e.cap > e.flow && d[u] == d[e.to] + 1) {
ok = true;
p[e.to] = G[u][i];
cur[u] = i;
u = e.to;
break;
}
}
if (!ok) {
int Min = n - 1;
for (int i = 0;i < G[u].size();++i) {
Edge& e = edges[G[u][i]];
if (e.cap > e.flow) Min = min(Min, d[e.to]);
}
if (--num[d[u]] == 0) break;
num[d[u] = Min + 1]++;
cur[u] = 0;
if (u != s) u = edges[p[u]].from;
}
}
return ret;
}
}solve;
int main(int argc, const char * argv[])
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
// clock_t _ = clock();
int N, F, D;
while(~scanf("%d%d%d", &N, &F, &D)) {
int s = F + D + N*2 + 1;
int t = F + D + N*2 + 2;
solve.init(t);
int f, d;
for (int i = 1;i <= N;++i) {
scanf("%d%d", &f, &d);
int x;
while(f--) {
scanf("%d", &x);
solve.addedge(x, i + F + D, 1);
}
solve.addedge(i + F + D, i + F + D + N, 1);
while(d--) {
scanf("%d", &x);
solve.addedge(i + F + D + N, F + x, 1);
}
}
for (int i = 1;i <= F;++i) {
solve.addedge(s, i, 1);
}
for (int i = 1;i <= D;++i) {
solve.addedge(i + F, t, 1);
}
int ans = solve.MaxFlow(s, t);
cout << ans << endl;
}
// printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
return 0;
}