常见的多限制匹配问题,每头牛需要选择一种食物和一种饮料,每种食物和饮料只能被一头牛选到,所以直接建图,分三部分,左边为所有的食物,和源连边,容量为1,右边是饮料,和汇连边,容量为1,为了达到每头牛都只能选择一种食物和饮料的目的,中间为牛,每头牛拆成两个点,两个点连边,容量为1,点1和食物连,点2和饮料连,在这基础上直接跑最大流即可。
我的代码:
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; const int MAX=402; const int oo=0x3f3f3f3f; struct Edge{ int num,ne,cap; }e[MAX*MAX]; int pre[MAX],pree[MAX],low[MAX],p[MAX]; int gap[MAX],cur[MAX],dist[MAX]; int n,st,ed,K; int get(){ char ch; bool flag=false; int ret=0; while((ch=getchar())<'0'||ch>'9')if(ch=='-')break; if(ch=='-')flag=true;else ret=ch-'0'; while((ch=getchar())>='0'&&ch<='9')ret=ret*10+ch-'0'; return ret; } int sap(){ int ret=0; bool done; memset(gap,0,sizeof(gap)); memset(dist,0,sizeof(dist)); memset(low,0,sizeof(low)); for(int i=0;i<n;i++){ cur[i]=p[i]; } gap[0]=n; low[st]=oo; int u=st; while(dist[st]<n){ done=true; for(int i=cur[u];~i;i=e[i].ne){ int v=e[i].num; cur[u]=i; if(e[i].cap&&dist[u]==dist[v]+1){ pre[v]=u;pree[v]=i; low[v]=min(low[u],e[i].cap); u=v; if(u==ed){ do{ e[pree[u]].cap-=low[ed]; e[pree[u]^1].cap+=low[ed]; u=pre[u]; }while(u!=st); ret+=low[ed]; } done=false; break; } } if(done){ gap[dist[u]]--; if(!gap[dist[u]])return ret; dist[u]=n; for(int i=p[u];~i;i=e[i].ne){ if(e[i].cap){ dist[u]=min(dist[u],dist[e[i].num]+1); } } gap[dist[u]]++; cur[u]=p[u]; if(u!=st)u=pre[u]; } } return ret; } void add(const int& u,const int& v,const int& cap){ e[K].num=v;e[K].cap=cap;e[K].ne=p[u];p[u]=K++; e[K].num=u;e[K].cap=0;e[K].ne=p[v];p[v]=K++; } int main(){ int np,f,d; int m1,m2,x; while(~scanf("%d%d%d",&np,&f,&d)){ n=2*np+f+d+2; st=0; ed=n-1; for(int i=0;i<n;i++)p[i]=-1;K=0; for(int i=1;i<=f;i++){ add(st,i,1); } for(int i=1;i<=d;i++){ add(i+2*np+f,ed,1); } for(int i=1;i<=np;i++){ add(i+f,i+np+f,1); } for(int i=1;i<=np;i++){ m1=get(); m2=get(); while(m1--){ x=get(); add(x,i+f,1); } while(m2--){ x=get(); add(i+f+np,x+f+2*np,1); } } printf("%d/n",sap()); } return 0; }