题面
Description
农夫JOHN为牛们做了很好的食品,但是牛吃饭很挑食. 每一头牛只喜欢吃一些食品和饮料而别的一概不吃.虽然他不一定能把所有牛喂饱,他还是想让尽可能多的牛吃到他们喜欢的食品和饮料. 农夫JOHN做了
F(1<=F<=100)
F
(
1
<=
F
<=
100
)
种食品并准备了
D(1<=D<=100)
D
(
1
<=
D
<=
100
)
种饮料. 他的
N(1<=N<=100)
N
(
1
<=
N
<=
100
)
头牛都以决定了是否愿意吃某种食物和喝某种饮料. 农夫JOHN想给每一头牛一种食品和一种饮料,使得尽可能多的牛得到喜欢的食物和饮料. 每一件食物和饮料只能由一头牛来用. 例如如果食物2被一头牛吃掉了,没有别的牛能吃食物2.
Input
1. 第一行: 三个数:
N,F,和D
N
,
F
,
和
D
2. 第2..N+1行: 每一行由两个数开始
Fi
F
i
和
Di,
D
i
,
分别是第i 头牛可以吃的食品数和可以喝的饮料数.下
Fi
F
i
个整数是第i头牛可以吃的食品号,再下面的
Di
D
i
个整数是第i头牛可以喝的饮料号码.
Output
3. 第一行: 一个整数,最多可以喂饱的牛数.
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} 中选
Sample Output
3
输出解释:
一个方案是:
Cow 1: 不吃
Cow 2: 食品 #2, 饮料 #2
Cow 3: 食品 #1, 饮料 #1
Cow 4: 食品 #3, 饮料 #3
用鸽笼定理可以推出没有更好的解 (一共只有3总食品和饮料).当然,别的数据会更难.
题解
网络流题目的关键就是建模,建模的关键就是根据题目的限制性条件,建立相关的边。
题中的限制性条件有:
1. 每头奶牛只能占用一份食物
2. 每份食物只能被一头奶牛吃
3. 一份食物由一份饮料和一份食品组成
所以我们根据每一份饮料、每一份食物、每一头奶牛建立相关的点。
然后建立一个超级源点,向每一份食物连容量为1的边;建立一个超级汇点,从每份饮料出发连一条容量为1的边;再根据奶牛的喜好,从食物向奶牛连容量为1边、从奶牛向饮料连容量为1的边。
一个意料之外的问题。看似已经建好图了。但是我们发现。这样有可能存在一只奶牛占用多份食物的可能性,所以我们要把所有奶牛拆成两个点。食物指向一个奶牛点,这个奶牛点再指向另外一个奶牛点,再由另外的奶牛点指向饮料。
code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int num=0;char c=' ';bool flag=true;
for(;c>'9'||c<'0';c=getchar())
if(c=='-')
flag=false;
for(;c>='0'&&c<='9';num=(num<<3)+(num<<1)+c-48,c=getchar());
return flag ? num : -num;
}
namespace graph{
const int maxn=500;
struct node{
int y,val,next;
}a[maxn*maxn];
int head[maxn],top;
void insert(int x,int y,int v){
a[top].y=y;
a[top].val=v;
a[top].next=head[x];
head[x]=top++;
}
int n,f,d,s,t;
//1~f食物
//f+1~f+n奶牛1
//f+n+1~f+2n奶牛2
//f+2n+1~f+2n+d食物
//0源点 f+2n+d+1汇点
void init(){
memset(head,-1,sizeof head);
n=read();f=read();d=read();
s=0;
t=2*n+f+d+1;
for(int i=1;i<=n;i++){
int F=read();
int D=read();
while(F--){
int x=read();
insert(x,f+i,1);
insert(f+i,x,0);
}
while(D--){
int x=read();
insert(f+i+n,f+2*n+x,1);
insert(f+2*n+x,f+i+n,0);
}
}
for(int i=1;i<=n;i++){
insert(f+i,f+i+n,1);
insert(f+i+n,f+i,0);
}
for(int i=1;i<=f;i++){
insert(0,i,1);
insert(i,0,0);
}
for(int i=1;i<=d;i++){
insert(f+2*n+i,t,1);
insert(t,f+2*n+i,0);
}
}
}using namespace graph;
namespace MAX_FLOW{
int vis[maxn],cur[maxn];
bool bfs(){
memset(vis,0,sizeof vis);
queue<int>q;
q.push(s);vis[s]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i+1;i=a[i].next){
int v=a[i].y;
if(vis[v]||a[i].val==0)continue;
vis[v]=vis[u]+1;
q.push(v);
if(v==t)return true;
}
}
return false;
}
int dfs(int x,int flow){
if(x==t)return flow;
for(int &i=cur[x];i+1;i=a[i].next){
int y=a[i].y;
if(vis[y]!=vis[x]+1||a[i].val==0)continue;
int k=dfs(y,min(flow,a[i].val));
if(k){
a[i].val-=k;
a[i^1].val+=k;
return k;
}
}
return 0;
}
}using namespace MAX_FLOW;
int main(){
init();
int ans=0;
const int INF=0x7fffffff;
while(bfs()){
for(int i=s;i<=t;i++)
cur[i]=head[i];
while(int flow=dfs(0,INF))
ans+=flow;
}
printf("%d\n",ans);
return 0;
}