像是二分图匹配问题,但不同的是每只牛有两种需求,必须同时满足
有个巧妙的方法,用网络流来完成,就是将图分为三层,食物,牛,饮料
然后一个源点连向食物,边权1,饮料连向汇点,边权1
牛就分为两个点,入点和出点,入点到出点连边,边权为1
然后牛需要的食物向牛的入点连边,牛的出点向牛需要的饮料连边
用ISAP算法跑一遍源点到汇点的最大流就可以了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=500+10;
const int M=50000+10;
const int INF=0x7f7f7f7f;
struct Edge
{
int to,nxt,cap,flow;
}edge[M];
int tot,first[N];
void addedge(int u,int v,int w,int rw=0)
{
edge[tot].to=v;edge[tot].cap=w;edge[tot].flow=0;
edge[tot].nxt=first[u];first[u]=tot++;
edge[tot].to=u;edge[tot].cap=rw;edge[tot].flow=0;
edge[tot].nxt=first[v];first[v]=tot++;
}
void init()
{
tot=0;
memset(first,-1,sizeof(first));
}
int gap[N],dep[N],pre[N],cur[N];
int sap(int s,int e,int n) //起点,终点,点个数
{
memset(gap,0,sizeof(gap));
memset(dep,0,sizeof(dep));
memcpy(cur,first,sizeof(first));
int u=s;
pre[u]=-1;
gap[0]=n;
int ans=0;
while(dep[s]<n)
{
if(u==e)
{
int Min=INF;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
if(Min>edge[i].cap-edge[i].flow)
Min=edge[i].cap-edge[i].flow;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
{
edge[i].flow+=Min;
edge[i^1].flow-=Min;
}
u=s;
ans+=Min;
continue;
}
bool flag=false;
int v;
for(int i=cur[u];i!=-1;i=edge[i].nxt)
{
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u])
{
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag)
{
u=v;
continue;
}
int Min=n;
for(int i=first[u];i!=-1;i=edge[i].nxt)
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
{
Min=dep[edge[i].to];
cur[u]=i;
}
gap[dep[u]]--;
if(!gap[dep[u]]) return ans;
dep[u]=Min+1;
gap[dep[u]]++;
if(u!=s) u=edge[pre[u]^1].to;
}
return ans;
}
int main()
{
int n,f,d;
int a,b,c;
while(~scanf("%d%d%d",&n,&f,&d))
{
init();
int num=f+d;
for(int i=1;i<=f;i++)
addedge(0,i,1);
for(int i=f+1;i<=num;i++)
addedge(i,num+1,1);
num++;
for(int i=1;i<=2*n;i+=2)
{
addedge(num+i,num+i+1,1);
scanf("%d%d",&a,&b);
for(int j=0;j<a;j++)
{
scanf("%d",&c);
addedge(c,num+i,1);
}
for(int j=0;j<b;j++)
{
scanf("%d",&c);
addedge(num+i+1,c+f,1);
}
}
printf("%d\n",sap(0,num,num+2*n+1));
}
return 0;
}