传送门
解析:
网络流建图入门题。
思路:
首先一看这是一个匹配问题,二分图匹配?
这显然不能用二分图匹配做。。。
因为每一头牛要匹配两个点。。
那么匹配问题的解法就还剩网络流。
怎么建图。
首先,每种食物和饮料分别只有一份。我们分别将它们向源点和汇点连容量为1的边,保证只有一份被记录在最终的方案中。
然后每头牛分别向它们喜欢的食物和饮料连边。
最后一步,也是很多匹配问题最容易忘记的一点,把牛拆点,连容量为111的边,保证每头牛只被前后匹配一次。
代码:
#include<iostream>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=403;
cs int M=30105;
cs int INF=0x3f3f3f3f;
int last[N],nxt[M<<1],to[M<<1],ecnt=1;
int cap[M<<1];
inline void addedge(int u,int v,int val){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,cap[ecnt]=val;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,cap[ecnt]=0;
}
cs int S=0,T=401;
int lev[N],cur[N];
inline bool BFS(){
memset(lev,-1,sizeof lev);
queue<int>q;
q.push(S),lev[S]=0,cur[S]=last[S];
while(!q.empty()){
int u=q.front();
q.pop();
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&lev[v]==-1){
lev[v]=lev[u]+1;
if(v==T)return true;
cur[v]=last[v];
q.push(v);
}
}
}
return false;
}
int Dinic(cs int &u,cs int &flow){
if(u==T)return flow;
int ans=0;
for(int &e=cur[u],v=to[e];e;v=to[e=nxt[e]]){
if(cap[e]&&lev[v]>lev[u]){
int delta=Dinic(v,min(flow-ans,cap[e]));
if(delta){
cap[e]-=delta;
cap[e^1]+=delta;
ans+=delta;
if(ans==flow)return ans;
}
}
}
return ans;
}
int maxflow(){
int ans=0;
while(BFS())ans+=Dinic(S,INF);
return ans;
}
int n,f,d;
signed main(){
n=getint(),f=getint(),d=getint();
for(int re i=1;i<=f;++i)addedge(S,i,1);
for(int re i=1;i<=d;++i)addedge(300+i,T,1);
for(int re i=1;i<=n;++i)addedge(100+i,200+i,1);
for(int re i=1;i<=n;++i){
int F=getint(),D=getint();
for(int re j=1;j<=F;++j){
int v=getint();
addedge(v,100+i,1);
}
for(int re j=1;j<=D;++j){
int v=getint();
addedge(200+i,300+v,1);
}
}
cout<<maxflow()<<endl;
return 0;
}