题目链接:poj 3281
给定n头牛,f种食物,d种饮料,每种食物、饮料只能分给一头牛,每头牛只能获得一种食物、饮料。每头牛都有自己喜好的饮料、食物。问:最多能有多少头牛同时获得喜好的食物和饮料。
较基础的网络流。
注意这里不再是二分图了,因为要同时匹配两种物质,因此可以把牛拆点,构造出 源->食物->牛1->牛2->饮料->汇的图,牛1、牛2 同种牛之间连容量为1的边,然后套用EK算法求最大流即可
//基础网络流
//要同时匹配drink和food,因此把牛拆点建 源->food->牛1->牛2->drink->汇的新图然后套用EK即可求解
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define FFF 405
int map[FFF][FFF],vis[FFF],pre[FFF],flow[FFF];
#define INF 23333333
int n,f,d;
queue<int> p;
int bfs(int source,int end)
{
memset(vis,false,sizeof(vis));
memset(flow,0,sizeof(flow));
flow[source]=INF;
vis[source]=true;
while(!p.empty())p.pop();
p.push(source);
while(!p.empty())
{
int now=p.front();p.pop();
for(int i=source;i<=end;i++)
{
if(!vis[i]&&map[now][i]>0)
{
vis[i]=true;
pre[i]=now;
flow[i]=min(flow[now],map[now][i]);
p.push(i);
}
}
}
return flow[end];
}
int maxflow(int source,int end)
{
int ans=0;
while(bfs(source,end))
{
int inc=flow[end];
ans+=inc;
int now=end;
while(now!=source)
{
int last=pre[now];
map[now][last]+=inc;
map[last][now]-=inc;
now=last;
}
}
return ans;
}
int main()
{
scanf("%d%d%d",&n,&f,&d);
memset(map,0,sizeof(map));
for(int i=1;i<=f;i++)
map[0][i]=1;
for(int i=1;i<=d;i++)
map[2*n+f+i][2*n+f+d+1]=1;
for(int i=1;i<=n;i++)
{
map[f+i][n+f+i]=1;
}
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
for(int j=1;j<=x;j++)
{
int z;
scanf("%d",&z);
map[z][i+f]=1;
}
for(int j=1;j<=y;j++)
{
int z;
scanf("%d",&z);
map[f+n+i][f+2*n+z]=1;
}
}
cout<<maxflow(0,2*n+f+d+1)<<endl;
return 0;
}