很巧妙的思想
转自:http://www.cnblogs.com/kuangbin/archive/2012/08/21/2649850.html
本题能够想到用最大流做,那真的是太绝了。建模的方法很妙!
题意就是有N头牛,F个食物,D个饮料。
N头牛每头牛有一定的喜好,只喜欢几个食物和饮料。
每个食物和饮料只能给一头牛。一头牛只能得到一个食物和饮料。
而且一头牛必须同时获得一个食物和一个饮料才能满足。问至多有多少头牛可以获得满足。
最初相当的是二分匹配。但是明显不行,因为要分配两个东西,两个东西还要同时满足。
最大流建图是把食物和饮料放在两端。一头牛拆分成两个点,两点之间的容量为1.喜欢的食物和饮料跟牛建条边,容量为1.
加个源点和汇点。源点与食物、饮料和汇点的边容量都是1,表示每种食物和饮料只有一个。
这样话完全是最大流问题了,。
Sample Input
4 3 3 2 2 1 2 3 1 //1号牛喜欢2种食物(1,2)2种饮料(3,1) 2 2 2 3 1 2 2 2 1 3 1 2 2 1 1 3 3
Sample Output
3
1 /* 2 POJ 3281 最大流 3 //源点-->food-->牛(左)-->牛(右)-->drink-->汇点 4 //精髓就在这里,牛拆点,确保一头牛就选一套food和drink的搭配 5 6 */ 7 8 #include<stdio.h> 9 #include<iostream> 10 #include<string.h> 11 #include<algorithm> 12 #include<queue> 13 using namespace std; 14 15 //**************************************************** 16 //最大流模板 17 //初始化:g[][],start,end 18 //****************************************************** 19 const int MAXN=500; 20 const int INF=0x3fffffff; 21 int g[MAXN][MAXN];//存边的容量,没有边的初始化为0 22 int path[MAXN],flow[MAXN],start,end; 23 int n;//点的个数,编号0-n.n包括了源点和汇点。 24 25 queue<int>q; 26 int bfs() 27 { 28 int i,t; 29 while(!q.empty())q.pop();//把清空队列 30 memset(path,-1,sizeof(path));//每次搜索前都把路径初始化成-1 31 path[start]=0; 32 flow[start]=INF;//源点可以有无穷的流流进 33 q.push(start); 34 while(!q.empty()) 35 { 36 t=q.front(); 37 q.pop(); 38 if(t==end)break; 39 //枚举所有的点,如果点的编号起始点有变化可以改这里 40 for(i=0;i<=n;i++) 41 { 42 if(i!=start&&path[i]==-1&&g[t][i]) 43 { 44 flow[i]=flow[t]<g[t][i]?flow[t]:g[t][i]; 45 q.push(i); 46 path[i]=t; 47 } 48 } 49 } 50 if(path[end]==-1)return -1;//即找不到汇点上去了。找不到增广路径了 51 return flow[end]; 52 } 53 int Edmonds_Karp() 54 { 55 int max_flow=0; 56 int step,now,pre; 57 while((step=bfs())!=-1) 58 { 59 max_flow+=step; 60 now=end; 61 while(now!=start) 62 { 63 pre=path[now]; 64 g[pre][now]-=step; 65 g[now][pre]+=step; 66 now=pre; 67 } 68 } 69 return max_flow; 70 } 71 int main() 72 { 73 int N,F,D; 74 while(scanf("%d%d%d",&N,&F,&D)!=EOF) 75 { 76 memset(g,0,sizeof(g)); 77 n=F+D+2*N+1; 78 start=0; 79 end=n; 80 for(int i=1;i<=F;i++)g[0][i]=1; 81 for(int i=F+2*N+1;i<=F+2*N+D;i++)g[i][n]=1; 82 for(int i=1;i<=N;i++)g[F+2*i-1][F+2*i]=1; 83 int k1,k2; 84 int u; 85 for(int i=1;i<=N;i++) 86 { 87 scanf("%d%d",&k1,&k2); 88 while(k1--) 89 { 90 scanf("%d",&u); 91 g[u][F+2*i-1]=1; 92 } 93 while(k2--) 94 { 95 scanf("%d",&u); 96 g[F+2*i][F+2*N+u]=1; 97 } 98 } 99 printf("%d ",Edmonds_Karp()); 100 } 101 return 0; 102 }