Description
农夫JOHN为牛们做了很好的食品,但是牛吃饭很挑食. 每一头牛只喜欢吃一些食品和饮料而别的一概不吃.虽然他不一定能把所有牛喂饱,他还是想让尽可能多的牛吃到他们喜欢的食品和饮料. 农夫JOHN做了F (1 <= F <= 100) 种食品并准备了D (1 <= D <= 100) 种饮料. 他的N (1 <= N <= 100)头牛都以决定了是否愿意吃某种食物和喝某种饮料. 农夫JOHN想给每一头牛一种食品和一种饮料,使得尽可能多的牛得到喜欢的食物和饮料. 每一件食物和饮料只能由一头牛来用. 例如如果食物2被一头牛吃掉了,没有别的牛能吃食物2.
Input
* 第一行: 三个数: N, F, 和 D
* 第2..N+1行: 每一行由两个数开始F_i 和 D_i, 分别是第i 头牛可以吃的食品数和可以喝的饮料数.下F_i个整数是第i头牛可以吃的食品号,再下面的D_i个整数是第i头牛可以喝的饮料号码.
Output
* 第一行: 一个整数,最多可以喂饱的牛数.
Sample Input
4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3
输入解释:
牛 1: 食品从 {1,2}, 饮料从 {1,2} 中选
牛 2: 食品从 {2,3}, 饮料从 {1,2} 中选
牛 3: 食品从 {1,3}, 饮料从 {1,2} 中选
牛 4: 食品从 {1,3}, 饮料从 {3} 中选
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3
输入解释:
牛 1: 食品从 {1,2}, 饮料从 {1,2} 中选
牛 2: 食品从 {2,3}, 饮料从 {1,2} 中选
牛 3: 食品从 {1,3}, 饮料从 {1,2} 中选
牛 4: 食品从 {1,3}, 饮料从 {3} 中选
Sample Output
3
输出解释:
一个方案是:
Cow 1: 不吃
Cow 2: 食品 #2, 饮料 #2
Cow 3: 食品 #1, 饮料 #1
Cow 4: 食品 #3, 饮料 #3
用鸽笼定理可以推出没有更好的解 (一共只有3总食品和饮料).当然,别的数据会更难.
输出解释:
一个方案是:
Cow 1: 不吃
Cow 2: 食品 #2, 饮料 #2
Cow 3: 食品 #1, 饮料 #1
Cow 4: 食品 #3, 饮料 #3
用鸽笼定理可以推出没有更好的解 (一共只有3总食品和饮料).当然,别的数据会更难.
HINT
……看上去就是一个“三分图匹配”??
比较裸的最大流。。
建图错了好几次= =
注意每头牛只会吃一份食物。。。
#include<bits/stdc++.h>
using namespace std;
const int
N=105,
M=405,
inf=100000000;
int n,F,D,Ecnt;
int source,sink,POINTS;
int d[M],gap[M],Q[M],pre[M];
struct Edge{
int next,to,C;
}E[(N+(N*N<<1))<<1];int head[M],cur[M];
void add(int u,int v,int C){
E[Ecnt].next=head[u];
E[Ecnt].to=v;
E[Ecnt].C=C;
head[u]=Ecnt++;
}
void BFS(){
memset(d,255,sizeof(d));
memset(gap,0,sizeof(gap));
gap[0]=1,d[sink]=0;
int h=0,t=1;Q[0]=sink;
while (h<t){
int u=Q[h++];
for (int i=head[u];~i;i=E[i].next){
int v=E[i].to;
if (~d[v]) continue;
d[v]=d[u]+1,gap[d[v]]++;
Q[t++]=v;
}
}
}
int ISAP(){
BFS();
memcpy(cur,head,sizeof(cur));
int flow=0,u=source;pre[u]=u;
while (d[sink]<POINTS+1){
if (u==sink){
int f=inf,neck;
for (int i=source;i!=sink;i=E[cur[i]].to)
if (f>E[cur[i]].C) f=E[cur[i]].C,neck=i;
for (int i=source;i!=sink;i=E[cur[i]].to)
E[cur[i]].C-=f,E[cur[i]^1].C+=f;
flow+=f,u=neck;
}
int j;
for (j=cur[u];~j;j=E[j].next)
if (E[j].C && d[E[j].to]+1==d[u]) break;
if (~j) pre[E[j].to]=u,cur[u]=j,u=E[j].to;
else{
if (!(--gap[d[u]])) break;
int mind=POINTS+1;
for (int i=head[u];~i;i=E[i].next)
if (E[i].C && mind>d[E[i].to])
mind=d[E[i].to],cur[u]=i;
d[u]=mind+1,gap[d[u]]++;
u=pre[u];
}
}
return flow;
}
void build(){
memset(head,255,sizeof(head));
int tf,td,x;
POINTS=(n<<1)+F+D+2,Ecnt=0;
source=(n<<1)+F+D+1,sink=source+1;
for (int i=1;i<=n;i++){
scanf("%d%d",&tf,&td);
add((i<<1)-1,i<<1,1),add(i<<1,(i<<1)-1,0);
for (int j=1;j<=tf;j++){
scanf("%d",&x);
add(i<<1,x+(n<<1),1),add(x+(n<<1),i<<1,0);
}
for (int j=1;j<=td;j++){
scanf("%d",&x);
add(x+(n<<1)+F,(i<<1)-1,1),add((i<<1)-1,x+(n<<1)+F,0);
}
}
for (int i=(n<<1)+F+1;i<=(n<<1)+F+D;i++) add(source,i,1),add(i,source,0);
for (int i=(n<<1)+1;i<=(n<<1)+F;i++) add(i,sink,1),add(sink,i,0);
}
int main(){
scanf("%d%d%d",&n,&F,&D);
build();
printf("%d\n",ISAP());
return 0;
}