题目大意:一个农场场主,为他的n头牛做了f种食物和d种饮料,每头牛都有他喜欢的食物和饮料,而且,每个食物或饮料都只能给一头牛食用,问最多能同时满足多少头牛的饮食。
解题思路:这个题目我只记得我一开始看网络流的时候看到过,当时这个构图并不会,但现在看起来好像就没当初那么难了。这个题目如果只有食物和牛的话就有点二分图的意思了,可是加了喜欢的饮料,所以需要网络流做。难点当然在构图,看到这个题目的第一感觉是从源点到牛有边权值为2表示一头牛需要两样东西满足,牛到喜欢的饮料和食物分别有边权值为1,然后食物饮料到汇点有边权值为1表示只能有一个牛使用,然后看看最大流的流值的一半就是牛的个数,但是明显不对,因为2个流值可能不同属于一头牛,但是最直观的想法往往可以反应问题,不过需要更加苛刻的限制,这样就想到了一牛一流,也就是食物连牛,权值为1,牛连饮料,权值为1,食物饮料分别连接原点和汇点,权值都是1。构图完成,流的最大值就是牛的个数。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define maxn 510
#define INF 1e9
using namespace std;
struct edge{
edge(){};
edge(int from,int to,int val,int flow):from(from),to(to),val(val),flow(flow){}
int from,to,val,flow;
};
int n,m,f,d;
vector<edge>p;
vector<int>num[maxn];
bool visit[maxn];
int dis[maxn];
int cur[maxn];
void add(int x,int y,int z){
p.push_back(edge(x,y,z,0));
p.push_back(edge(y,x,0,0));
int xx=p.size();
num[x].push_back(xx-2);
num[y].push_back(xx-1);
}
bool bfs(int s,int t){
int i,j;
memset (visit,0,sizeof(visit));
queue<int>qq;
qq.push(s);
dis[s]=0;
visit[s]=1;
while (!qq.empty()){
int u=qq.front();
qq.pop();
for (i=0;i<num[u].size();i++){
edge& e=p[num[u][i]];
if (!visit[e.to]&&e.val>e.flow){
visit[e.to]=1;
dis[e.to]=dis[u]+1;
qq.push(e.to);
}
}
}
return visit[t];
}
int dfs(int x,int t,int val){
if (x==t||val==0){
return val;
}
int flow=0,f;
for (int& i=cur[x];i<num[x].size();i++){
edge& e=p[num[x][i]];
if (dis[x]+1==dis[e.to]&&(f=dfs(e.to,t,min(val,e.val-e.flow)))>0){
e.flow+=f;
p[num[x][i]^1].flow-=f;
flow+=f;
val-=f;
if (val==0)break;
}
}
return flow;
}
int dinic(int s,int t){
int flow=0;
while (bfs(s,t)){
memset (cur,0,sizeof(cur));
flow+=dfs(s,t,INF);
}
return flow;
}
int main(){
int i,j,k,l,x,y,z,t;
while (scanf("%d%d%d",&n,&f,&d)!=EOF){
int total=2*n+d+f+1;
for (i=1;i<=f;i++)add(0,i,1);
for (i=1;i<=d;i++)add(i+2*n+f,total,1);
for (i=1+f;i<=n+f;i++){
add(i,n+i,1);
scanf("%d%d",&x,&y);
while (x--){
scanf("%d",&z);
add(z,i,1);
}
while (y--){
scanf("%d",&z);
add(n+i,z+2*n+f,1);
}
}
printf("%d\n",dinic(0,total));
}
}