题目描述:
有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。(1 <= f <= 100, 1 <= d <= 100, 1 <= n <= 100)
题解:
将每头牛拆分成两个点,中间用边权为1的点连接,保证每头牛最多只会被利用一次
然后构图,超级源点->食物->牛的入点->牛的出点->饮料->超级汇点跑一遍最大流
其实难点主要就是构图(废话)
注释在↓
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define LL long long
const int MAXN = 5e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int n,m,k,s,t,tot=1,head[MAXN],to[MAXN],nxt[MAXN],w[MAXN],h[MAXN];
int a[MAXN],b[MAXN];
inline void ade(int u,int v,int ww){
to[++tot]=v; w[tot]=ww; nxt[tot]=head[u]; head[u]=tot;
}
inline void add(int u,int v,int w){ ade(u,v,w); ade(v,u,0); }
inline int bfs(){
queue<int> que; que.push(s); memset(h,0,sizeof(h)); h[s]=1;
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u];i;i=nxt[i]){
if(w[i] && !h[to[i]]){
h[to[i]]=h[u]+1; que.push(to[i]);
}
}
}
return h[t];
}
inline int dfs(int x,int f){
if(x==t) return f; int fl=0;
for(int i=head[x];i&&f;i=nxt[i]){
if(w[i] && h[to[i]]==h[x]+1){
int mi=dfs(to[i],min(f,w[i]));
w[i]-=mi; w[i^1]+=mi; fl+=mi; f-=mi;
}
}
if(!fl) h[x]=-1;
return fl;
}
inline int dinic(){
int res=0;
while(bfs()) res+=dfs(s,INF);
return res;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
#endif // ONLINE_JUDGE
scanf("%d%d%d",&n,&m,&k); s=0,t=2*n+m+k+1;
for(int i=1;i<=m;i++) add(s,i,1);//超级源点连食物
for(int i=1;i<=k;i++) add(2*n+m+i,t,1);//饮料连超级汇点
for(int i=1;i<=n;i++){
int f,d; scanf("%d%d",&f,&d);
add(m+i,m+n+i,1);//牛的入点和出点相连
for(int j=1,x;j<=f;j++) scanf("%d",&x),add(x,i+m,1);//食物连牛的入点
for(int j=1,x;j<=d;j++) scanf("%d",&x),add(n+m+i,x+m+2*n,1);//牛的出点连饮料
}
printf("%d\n",dinic());
return 0;
}