题目:
Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.
Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not be able to stuff everybody, he wants to give a complete meal of both food and drink to as many cows as possible.
Farmer John has cooked F (1 ≤ F ≤ 100) types of foods and prepared D (1 ≤ D ≤ 100) types of drinks. Each of his N (1 ≤ N ≤ 100) cows has decided whether she is willing to eat a particular food or drink a particular drink. Farmer John must assign a food type and a drink type to each cow to maximize the number of cows who get both.
Each dish or drink can only be consumed by one cow (i.e., once food type 2 is assigned to a cow, no other cow can be assigned food type 2).
输入:
Line 1: Three space-separated integers: N, F, andD
Lines 2.. N+1: Each line i starts with a two integers Fi and Di, the number of dishes that cowi likes and the number of drinks that cow ilikes. The next Fi integers denote the dishes that cow i will eat, and the Di integers following that denote the drinks that cow i will drink.
输出:
Line 1: A single integer that is the maximum number of cows that can be fed both food and drink that conform to their wishes
样例输入:
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
样例输出:
3
题意:一共有N头奶牛,F中食物,D种饮料。每头奶牛要吃到自己喜欢的食物和饮料,并且食物和饮料必须是一个类型的,比如它吃了1类型的食物,就必须喝1类型的饮料。只有吃的食物和饮料都是自己喜欢的,它才会高兴。求最多有几头奶牛会高兴。输入的数首先是N,F,D,然后接下来的每一行的前两个数Fi,Di分别表示这头牛喜欢的食物和饮料的种类,然后接下来的Fi个数是这头牛喜欢的具体类型,后面Di个数表示这头牛喜欢的饮料的类型。
思路:要把奶牛拆成两个点。因为如果不拆开的话,一头牛可能会贪吃(吃多种类型的食物和饮料,从而让别的牛吃不着东西),借用一下别人的图来理解一下。
1.当牛不拆开的情况
1通过4到5之后,2还可以通过4到6,造成一头牛贪吃
2.当牛拆开的时候
1通过4通过8到5,之后,4到8这条路已经没有流量了,所以不能再走了,所以就避免了一头牛吃多种食物的情况
牛1是从1到n,牛2是从1+N到2N,食物是从2N+1到2N+F,饮料是从2N+F+1到2N+F+D,超级源点是0,超级汇点是2N+F+D+1
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn=2000;//开太小会runti error
const int INF=0x3f3f3f3f;
int cnt,n,f,d;
int s,T;
int head[maxn],dis[maxn],cur[maxn];
struct edge
{
int u,v,c,next;
}node[maxn*2];
void add(int u,int v,int c)
{
node[cnt].u=u;
node[cnt].v=v;
node[cnt].c=c;
node[cnt].next=head[u];
head[u]=cnt++;
}
bool bfs()
{
memset(dis,0,sizeof(dis));
queue<int>q;
dis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=node[i].next)
{
edge e=node[i];
if(!dis[e.v]&&e.c>0)
{
dis[e.v]=dis[e.u]+1;
q.push(e.v);
if(e.v==T)return 1;
}
}
}
return dis[T]!=0;
}
int dfs(int u,int mx)
{
int ret=0;
if(u==T || mx==0) return mx;
for(int &i=cur[u];i!=-1;i=node[i].next)
{
edge e=node[i];
if(dis[e.v]==dis[e.u]+1&&e.c>0)
{
int w=dfs(e.v,min(mx,e.c));
node[i].c-=w;
node[i^1].c+=w;
ret+=w;
mx-=w;
if(mx==0) break;
}
}
return ret;
}
int dinic()
{
int maxflow=0;
while(bfs())
{
memcpy(cur,head,sizeof(head));
maxflow+=dfs(s,INF);
}
return maxflow;
}
int main()
{
while(~scanf("%d%d%d",&n,&f,&d))
{
int ff,dd;
T=2*n+f+d+1;
s=0;
memset(head,-1,sizeof(head));
cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&ff,&dd);
for(int j=1;j<=ff;j++)
{
int fi;
scanf("%d",&fi);//食物和牛1连接
add(2*n+fi,i,1);
add(i,2*n+fi,0);
}
for(int j=1;j<=dd;j++)//牛2和饮料连接
{
int di;
scanf("%d",&di);
add(n+i,2*n+f+di,1);
add(2*n+f+di,n+i,0);
}
add(i,i+n,1);//牛1和牛2连接
add(i+n,i,0);
}
for(int j=1;j<=f;j++)//超级源点和食物连接
{
add(0,2*n+j,1);
add(2*n+j,0,0);
}
for(int j=1;j<=d;j++)//超级汇点和饮料连接
{
add(2*n+f+j,T,1);
add(T,2*n+f+j,0);
}
printf("%d\n",dinic());
}
return 0;
}