POJ3281——Dining(最大流)
很简单的一个网络流
为了保证所有的食物和饮料都和牛连上
把牛放在中间
为了保证所有的牛都只被算一次
每个牛作两个点,中间连一条容量为1的边
跑最大流就可以了
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<cstdlib>
#include<cstring>
#include<string.h>
#include<cmath>
#include<math.h>
using namespace std;
int adj[100005],nxt[100005],to[100005],cap[100050],lev[100005],n,str,des,cnt=1,f,d;
inline int read(){
char ch=getchar();
int res=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
return res;
}
inline void addedge(int u,int v,int w)
{
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,cap[cnt]=w;
nxt[++cnt]=adj[v];adj[v]=cnt,to[cnt]=u,cap[cnt]=0;
}
inline bool bfs(){
queue<int>q;int v;
memset(lev,-1,sizeof(lev));
q.push(str),lev[str]=0;
while(!q.empty())
{
int u=q.front();q.pop();
for(int e=adj[u];e;e=nxt[e])
{
if(cap[e]>0&&lev[v=to[e]]==-1)
{
lev[v]=lev[u]+1,q.push(v);
if(v==des) return true;
}
}
}
return false;
}
inline int dfs(int u,int flow)
{
if(u==des)return flow;
int res=0,v,flw;
for(int e=adj[u];e;e=nxt[e])
{
if(cap[e]>0&&lev[u]<lev[v=to[e]])
{
flw=dfs(v,min(cap[e],flow-res));
if(flw==0) lev[v]=-1;
cap[e]-=flw,cap[e^1]+=flw;
res+=flw;if(res==flow) break;
}
}
return res;
}
inline int dinic(){
int ans=0;
while(bfs())ans+=dfs(str,1<<30);
return ans;
}
int main(){
n=read(),f=read(),d=read();
for(int i=1;i<=f;i++)
addedge(1,i+1,1);
int dr,fo;
str=1,des=1+f+2*n+d+1;
for(int i=1;i<=n;i++)
{
fo=read(),dr=read();
for(int j=1;j<=fo;j++)
{
int fd=read();
addedge(fd+1,f+1+i,1);
}
for(int j=1;j<=dr;j++)
{
int dk=read();
addedge(f+n+1+i,2*n+f+1+dk,1);
}
}
for(int i=f+1+1;i<=f+1+n;i++)
{
addedge(i,i+n,1);
}
for(int i=f+2*n+1+1;i<=2*n+f+1+d;i++)
{
addedge(i,des,1);
}
cout<<dinic()<<endl;
return 0;
}