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: N, F, 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 }