luogu2891 [USACO07OPEN]吃饭Dining
题目大意:
有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。
解题方法:
这题算是网络流入门题,主要考如何构图,将食物置于左侧,牛置于中间,饮料置于右侧,依次连边,这样会发现无法满足每头牛只享用最多一种食物和一种饮料的条件。
所以可将中间的每个牛拆成两个点,两点之间连一条流量为1的边,最后源点向所有食物连流量为1的边,所以饮料向汇点连流量为1的边,跑网络流即可。
代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<queue> 8 using namespace std; 9 const int MAXN=11000; 10 const int INF=0x7fffffff; 11 struct Edge 12 { 13 int v,c,next; 14 }ed[MAXN*20]; 15 int n,f,d; 16 int dis[MAXN]; 17 int nume=-1,head[MAXN]={0},cru[MAXN]={0}; 18 void add_edge(int u,int v,int c) 19 { 20 nume++; 21 ed[nume].v=v; 22 ed[nume].c=c; 23 ed[nume].next=head[u]; 24 head[u]=nume; 25 nume++; 26 ed[nume].v=u; 27 ed[nume].c=0; 28 ed[nume].next=head[v]; 29 head[v]=nume; 30 } 31 bool BFS(int s,int t) 32 { 33 queue<int> team; 34 team.push(s); 35 memset(dis,0,sizeof(dis)); 36 dis[s]=1; 37 while(!team.empty()) 38 { 39 int u=team.front(); 40 team.pop(); 41 for(int i=head[u];i+1;i=ed[i].next) 42 if(!dis[ed[i].v] && ed[i].c>0) 43 { 44 dis[ed[i].v]=dis[u]+1; 45 team.push(ed[i].v); 46 } 47 } 48 return dis[t]; 49 } 50 int DFS(int now,int t,int flow) 51 { 52 if(now==t) return flow; 53 int s=0,k; 54 for(int &i=cru[now];i+1;i=ed[i].next) 55 { 56 int to=ed[i].v; 57 if(ed[i].c>0 && dis[to]==dis[now]+1) 58 { 59 k=DFS(to,t,min(flow-s,ed[i].c)); 60 s+=k; 61 ed[i].c-=k;ed[i^1].c+=k; 62 if(s==flow) break; 63 } 64 } 65 if(s==0) dis[now]=0; 66 return s; 67 } 68 int Dinic(int s,int t) 69 { 70 int ans=0; 71 while(BFS(s,t)) 72 { 73 memcpy(cru,head,sizeof(head)); 74 ans+=DFS(s,t,INF); 75 } 76 return ans; 77 } 78 int main() 79 { 80 int s,t; 81 scanf("%d%d%d",&n,&f,&d); 82 s=0;t=n*2+f+d; 83 memset(head,-1,sizeof(head)); 84 for(int i=1;i<=f;i++) add_edge(s,i,1); 85 for(int i=1;i<=n;i++) add_edge(f+i,f+i+n,1); 86 for(int i=1;i<=d;i++) add_edge(2*n+f+i,t,1); 87 for(int i=1;i<=n;i++) 88 { 89 int numf,numd; 90 scanf("%d%d",&numf,&numd); 91 int x; 92 for(int j=1;j<=numf;j++) 93 { 94 scanf("%d",&x); 95 add_edge(x,i+f,1); 96 } 97 for(int j=1;j<=numd;j++) 98 { 99 scanf("%d",&x); 100 add_edge(n+i+f,2*n+f+x,1); 101 } 102 } 103 printf("%d",Dinic(s,t)); 104 return 0; 105 }