题意:有N个牛,F个食物,D个饮料,每个牛喜欢一些食物和饮料,现在要给牛分发食物和饮料,当一个牛得到一个喜欢的食物和一个喜欢的饮料的时候,就说这个牛被满足了。求最多可以满足多少个牛。每个饮料和食物只能被分给一个牛,每个牛也只能拿到一个饮料和食物。
题解:按流建图,一个合法的流应该是:一个牛以及一个喜欢的饮料一个喜欢的食物。一头牛贡献一单位的流量,所以把牛拆了,中间加一个1容量的边,然后起点到所有饮料连1容量边,饮料到喜欢自己的牛连1容量边,牛到他喜欢的食物连1容量的边,所有食物向终点连1容量的边。这样一个流就必须经过 饮料-牛-食物,且这个饮料和食物都是牛喜欢的,而且把牛拆了可以起到流量限制的作用,使得一个牛只占有一个饮料和食物,不会暴饮暴食(雾。
Code:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 105;
int tot,first[maxn*4],nxt[maxn*maxn*16],des[maxn*maxn*16],flow[maxn*maxn*16];
int dep[maxn*4];
const int INF = 0x3f3f3f3f;
int d,f,n;
int ss,tt;
inline void addEdge(int x,int y,int z){
tot++;
des[tot] =y;
flow[tot] =z;
nxt[tot] = first[x];
first[x] = tot;
tot++;
des[tot] =x;
flow[tot] =0;
nxt[tot] = first[y];
first[y] =tot;
}
void input(){
memset(first,-1,sizeof first);
scanf("%d%d%d",&n,&f,&d);
for (int i=1;i<=n;i++){
int di,fi,x;
scanf("%d%d",&fi,&di);
for (int j=0;j<fi;j++){
scanf("%d",&x);
addEdge(2*n+x,i,1);
}
for (int j=0;j<di;j++){
scanf("%d",&x);
addEdge(n+i,2*n+f+x,1);
}
}
for (int i=1;i<=f;i++){
addEdge(0,2*n+i,1);
}
for (int i=1;i<=d;i++){
addEdge(2*n+f+i,2*n+f+d+1,1);
}
for (int i=1;i<=n;i++){
addEdge(i,i+n,1);
}
}
bool bfs(){
queue<int> Q;
memset(dep,-1,sizeof dep);
dep[ss] =0;
Q.push(ss);
while (!Q.empty()){
int q = Q.front();Q.pop();
for (int t = first[q];t!=-1;t=nxt[t]){
int v = des[t];
int c = flow[t];
if (c&&dep[v]==-1){
dep[v] = dep[q]+1;
Q.push(v);
}
}
}
return dep[tt]!=-1;
}
int dfs(int node,int now){
if (node==tt)return now;
int ret =0;
for (int t = first[node];t!=-1&&ret<now;t= nxt[t]){
int v = des[t];
int c = flow[t];
if (c&&dep[v]==dep[node]+1){
int x = min(c,now-ret);
x = dfs(v,x);
flow[t]-=x;
flow[t^1]+=x;
ret +=x;
}
}
if (!ret) dep[node] =-1;
return ret;
}
int max_flow(){
int tot =0;
while (bfs()){
int del =0;
while (del = dfs(ss,INF)){
tot+=del;
}
}
return tot;
}
void solve(){
ss =0;
tt =2*n+f+d+1;
printf("%d\n",max_flow());
}
int main(){
tot =-1;
input();
solve();
return 0;
}