码迷,mamicode.com
首页 > 编程语言 > 详细

POJ 3281 Dining 最大流 Dinic算法

时间:2015-06-15 00:14:03      阅读:231      评论:0      收藏:0      [点我收藏+]

标签:

Dining
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 10768   Accepted: 4938

Description

Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.

Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not be able to stuff everybody, he wants to give a complete meal of both food and drink to as many cows as possible.

Farmer John has cooked F (1 ≤ F ≤ 100) types of foods and prepared D (1 ≤ D ≤ 100) types of drinks. Each of his N (1 ≤ N ≤ 100) cows has decided whether she is willing to eat a particular food or drink a particular drink. Farmer John must assign a food type and a drink type to each cow to maximize the number of cows who get both.

Each dish or drink can only be consumed by one cow (i.e., once food type 2 is assigned to a cow, no other cow can be assigned food type 2).

Input

Line 1: Three space-separated integers: NF, and D 
Lines 2..N+1: Each line i starts with a two integers Fi and Di, the number of dishes that cow i likes and the number of drinks that cow i likes. The next Fi integers denote the dishes that cowi will eat, and the Di integers following that denote the drinks that cow i will drink.

Output

Line 1: A single integer that is the maximum number of cows that can be fed both food and drink that conform to their wishes

Sample Input

4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3

Sample Output

3

Hint

One way to satisfy three cows is: 
Cow 1: no meal 
Cow 2: Food #2, Drink #2 
Cow 3: Food #1, Drink #1 
Cow 4: Food #3, Drink #3 
The pigeon-hole principle tells us we can do no better since there are only three kinds of food or drink. Other test data sets are more challenging, of course.

Source

 
 
 
 
 
 
 
题意:农夫为他的牛准备了F种食物和D种饮料。每头牛都有各自喜欢的食物和饮料,而每种食物和饮料只能分配给一头牛。最多有多少头牛可以同时得到喜欢的食物和饮料?
 
我的第一道网络流的题目。
 
开始的思路:建立一个源点s和一个汇点t,然后把食物饮料和s,t建图,食物在前,饮料在后,然后把牛看成是流,跑一遍dinic,看有多少头牛可以到达t
 
这样的思路是错的:因为牛从s出发的时候不同的牛可以选择的路是不同的。
 
要怎么样才可以消除这种关系呢?
即怎么样才可以使得所有路径对所有流都是平等的,只有容量的限制。
 
 
再整理一下:
每头牛可以走的路径不一样
如果把牛,食物,饮料都看成是点,则每个点只可以经过一次。
 
所以建图:s,食物,牛,牛,饮料,t,正向容量都是1
 
s—食物的边,饮料—t的边的容量都是1,就保证了每种食物,饮料只被流经过一次
 
而牛—牛的边的容量为1,就保证了牛只被流经过一次
 
建图后,直接dinic即可。
 
值得说的是,这道题今晚8:30做到9:30左右AC了。
然后9:30的时候删掉,重新再打一次,结果第二次打错了,找bug找到现在才过,历时2hours。
 
原因:这个图是有向边,然后在addedge(from,to)的时候,我把部分边的起点和终点写反了。
 
这个一定要注意,下次不能再犯。
 
 
 
技术分享
  1 #include<cstring>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<vector>
  5 #include<queue>
  6 
  7 using namespace std;
  8 
  9 const int maxn=405;
 10 const int inf=0x3f3f3f3f;
 11 
 12 struct Edge
 13 {
 14     int to,cap,rev;
 15 };
 16 
 17 vector<Edge>edge[maxn];
 18 int level[maxn];
 19 int id[maxn];
 20 int s=0;
 21 int t;
 22 
 23 void addedge(int from,int to)
 24 {
 25     edge[from].push_back((Edge){to,1,edge[to].size()});
 26     edge[to].push_back((Edge){from,0,edge[from].size()-1});
 27 }
 28 
 29 void bfs()
 30 {
 31     memset(level,-1,sizeof(level));
 32 
 33     queue<int>que;
 34     while(!que.empty())
 35         que.pop();
 36 
 37     level[s]=0;
 38     que.push(s);
 39 
 40     while(!que.empty())
 41     {
 42         int u=que.front();
 43         que.pop();
 44         for(int i=0;i<edge[u].size();i++)
 45         {
 46             Edge &e=edge[u][i];
 47             if(e.cap>0&&level[e.to]<0)
 48             {
 49                 level[e.to]=level[u]+1;
 50                 que.push(e.to);
 51             }
 52         }
 53     }
 54 }
 55 
 56 int dfs(int u,int f)
 57 {
 58     if(u==t)
 59         return f;
 60     for(int &i=id[u];i<edge[u].size();i++)
 61     {
 62         Edge &e=edge[u][i];
 63         if(e.cap>0&&level[e.to]>level[u])
 64         {
 65             int d=dfs(e.to,min(e.cap,f));
 66             if(d>0)
 67             {
 68                 e.cap-=d;
 69                 edge[e.to][e.rev].cap+=d;
 70                 return d;
 71             }
 72         }
 73     }
 74     return 0;
 75 }
 76 
 77 int solve()
 78 {
 79     int res=0;
 80     while(true)
 81     {
 82         bfs();
 83         if(level[t]<0)
 84             return res;
 85         memset(id,0,sizeof(id));
 86         int flow;
 87         while(flow=dfs(s,inf))
 88         {
 89             res+=flow;
 90         }
 91     }
 92 }
 93 
 94 int main()
 95 {
 96     int N,F,D;
 97     while(~scanf("%d%d%d",&N,&F,&D))
 98     {
 99         for(int i=0;i<maxn;i++)
100             edge[i].clear();
101 
102         t=F+2*N+D+1;
103         for(int i=1;i<=F;i++)
104             addedge(s,i);
105         for(int i=1;i<=D;i++)
106             addedge(F+2*N+i,t);
107         for(int i=1;i<=N;i++)
108             addedge(i+F,i+F+N);
109         for(int i=1;i<=N;i++)
110         {
111             int a,b;
112             scanf("%d%d",&a,&b);
113             for(int j=1;j<=a;j++)
114             {
115                 int u;
116                 scanf("%d",&u);
117                 addedge(u,i+F);
118             }
119             for(int j=1;j<=b;j++)
120             {
121                 int u;
122                 scanf("%d",&u);
123                 addedge(i+F+N,u+F+2*N);
124             }
125         }
126 
127         printf("%d\n",solve());
128     }
129     return 0;
130 }
View Code

 

 

 

 

 

 

 

 

 

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

POJ 3281 Dining 最大流 Dinic算法

标签:

原文地址:http://www.cnblogs.com/-maybe/p/4576009.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!