题目:http://poj.org/problem?id=3281
网络流做图中的匹配,注意为了限制每头牛只匹配一种食物和一种饮料,要把牛拆成两个点,之间连边权为1的边。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; queue<int>q; int n,f,d,head[505],ct=1,inf=1e9,cur[505],ans,dep[505],t; struct N{ int to,next,w; N(int t=0,int n=0,int ww=0):to(t),next(n),w(ww) {} }edge[50005]; void add(int x,int y) { edge[++ct]=N(y,head[x],1);head[x]=ct; edge[++ct]=N(x,head[y],0);head[y]=ct; } bool bfs() { memset(dep,0,sizeof dep); while(q.size())q.pop(); q.push(0);dep[0]=1; while(q.size()) { int x=q.front();q.pop(); for(int i=head[x];i;i=edge[i].next) { int u=edge[i].to; if(!dep[u]&&edge[i].w) { dep[u]=dep[x]+1; q.push(u); } } } return dep[t]; } int dfs(int x,int f) { if(x==t)return f;// int res=0; for(int i=cur[x];i;i=edge[i].next) { int u=edge[i].to; if(dep[u]==dep[x]+1&&edge[i].w) { int tmp=dfs(u,min(edge[i].w,f-res)); edge[i].w-=tmp; edge[i^1].w+=tmp; res+=tmp; if(edge[i].w)cur[x]=i; if(res==f)return f; } } if(res==0)dep[x]=0; return res; } int main() { scanf("%d%d%d",&n,&f,&d); t=2*n+f+d+1; for(int i=1;i<=f;i++) add(0,i); for(int i=1;i<=n;i++) { int x,y,dc; scanf("%d%d",&x,&y); for(int j=1;j<=x;j++) { scanf("%d",&dc); add(dc,i+f); } add(i+f,i+n+f); for(int j=1;j<=y;j++) { scanf("%d",&dc); add(i+n+f,dc+2*n+f); } } for(int i=1;i<=d;i++) add(i+2*n+f,t); while(bfs()) { for(int i=0;i<=t;i++)cur[i]=head[i]; ans+=dfs(0,inf); } printf("%d",ans); return 0; }