poj 3281 最大流+建图

很巧妙的思想

转自: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\n",Edmonds_Karp());
100     }
101     return 0;
102 }

 

posted @ 2015-03-05 17:18  miao_a_miao  阅读(267)  评论(0编辑  收藏  举报