网络流的构图题。构图时设立超级源点和超级汇点。源点与每个食物连一条容量为1的边,汇点与每个饮料连一条容量为1的边。牛要拆点,入点与对应的食物连容量为1的边,出点和对应的饮料连一条容量为1的边。入点和出点间连一条容量的边。这样才能充分利用限制条件。最后求一次最大流即可。
构图题往往难度不大,只要充分利用已知的限制条件构造出图,套个模版即可。但构图的技巧很多,需要慢慢积累,大部分的网络流模型都很隐蔽,不是那么容易就看得出来的。
以下是代码:
- #include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int M=1000100;
const int N=1000;
const int INF=1<<29; - struct node
{
int u,v,cap,flow;
int next;
}edge[M];
int head[N],num;
int level[N];
int n,f,d,s,t; - void init()
{
int i;
for(i=0;i<=2*n+f+d+5;i++)
head[i]=-1;
num=0;
s=0;t=2*n+f+d+1;
} - void addege(int u,int v,int cap)
{
edge[num].u=u;
edge[num].v=v;
edge[num].cap=cap;
edge[num].flow=0;
edge[num].next=head[u];
head[u]=num++;
edge[num].u=v;
edge[num].v=u;
edge[num].cap=0;
edge[num].flow=0;
edge[num].next=head[v];
head[v]=num++;
} - int dinic_dfs(int sta,int end,int ver)
{
int stack[N*10],top=0;
int flow=0,cur,ptr,pre[N],minf,i;
int del[N];
for(i=0;i<=ver;i++)
{
del[i]=0;
}
stack[top++]=sta;
pre[sta]=sta;
cur=sta;
while(top)
{
while(cur!=end && top)
{
for(i=head[cur];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(level[v]==level[cur]+1 && edge[i].cap>edge[i].flow && !del[v])
{
stack[top++]=v;
cur=v;
pre[v]=i;
break;
}
}
if(i==-1)
{
del[cur]=1;
top--;
if(top)
cur=stack[top-1];
}
}
if(cur==end)
{
minf=INF;
while(cur!=sta)
{
cur=pre[cur];
if(edge[cur].cap-edge[cur].flow<minf) minf=edge[cur].cap-edge[cur].flow;
cur=edge[cur].u;
}
cur=end;
while(cur!=sta)
{
cur=pre[cur];
edge[cur].flow+=minf;
edge[cur^1].flow-=minf;
if(edge[cur].cap-edge[cur].flow==0)
{
ptr=edge[cur].u;
}
cur=edge[cur].u;
}
while(top>0 && stack[top-1]!=ptr) top--;
if(top) cur=stack[top-1];
flow+=minf;
}
}
return flow;
} - bool dinic_bfs(int sta,int end,int ver)
{
int queue[10*N];
int i,j;
for(i=0;i<=ver;i++)
{
level[i]=-1;
}
int rear=0;
queue[rear++]=sta;
level[sta]=0;
for(i=0;i<rear;i++)
{
for(j=head[queue[i]];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(level[v]==-1 && edge[j].cap>edge[j].flow)
{
level[v]=level[queue[i]]+1;
queue[rear++]=v;
}
}
}
return level[end]>=0;
} - int dinic(int sta,int end,int ver)
{
int flow=0,t;
while(dinic_bfs(sta,end,ver))
{
t=dinic_dfs(sta,end,ver);
if(t) flow+=t;
else break;
}
return flow;
} - int main()
{
scanf("%d%d%d",&n,&f,&d);
int i,j;
init();
for(i=1;i<=f;i++)
addege(s,i,1);
for(i=f+2*n+1;i<t;i++)
addege(i,t,1);
for(i=f+1;i<=f+n;i++)
{
addege(i,i+n,1);
int a,b,c;
scanf("%d%d",&a,&b);
for(j=0;j<a;j++)
{
scanf("%d",&c);
addege(c,i,1);
}
for(j=0;j<b;j++)
{
scanf("%d",&c);
addege(i+n,f+2*n+c,1);
}
}
printf("%d/n",dinic(s,t,t+1));
return 0;
}