Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 24945 | Accepted: 10985 |
Description數組
Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.ide
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.this
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.spa
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).code
Inputorm
Outputblog
Sample Inputthree
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 Outputip
3
Hintci
Source
都在代碼裏了,幹/drink.jpg
/* POJ 3281 最大流 + 拆點 源點 -> food -> 牛左 -> 牛右 -> Drink -> 匯點 建圖時注意將上面的全部邊的容量設置爲1,這樣就能夠保證一頭牛 只吃一種食物喝一種飲料,轉化以後確定就知道是最大流了 拆點技巧:爲了保證同一個東西知足兩個條件,則將其拆分爲兩個 公共邊的點分別進行求解。 嚶嚶嚶,爲何作完以後感受這個題其實建圖也是很好想的,就是拆個點,原諒本身太差 唉,都是幻覺 */ #include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <vector> using namespace std; const int maxn=1000+5, INF = 0x3f3f3f3f; struct Edge { Edge(){} Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){} int from,to,cap,flow; }; struct Dinic { int n,m,s,t; //結點數,邊數(包括反向弧),源點與匯點編號 vector<Edge> edges; //邊表 edges[e]和edges[e^1]互爲反向弧 vector<int> G[maxn]; //鄰接表,G[i][j]表示結點i的第j條邊在e數組中的序號 bool vis[maxn]; //BFS使用,標記一個節點是否被遍歷過 int d[maxn]; //從起點到i點的距離 int cur[maxn]; //當前弧下標 void init(int n,int s,int t) { this->n=n,this->s=s,this->t=t; for(int i=1;i<=n;i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap) { edges.push_back( Edge(from,to,cap,0) ); edges.push_back( Edge(to,from,0,0) ); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS() { memset(vis,false,sizeof(vis)); queue<int> Q;//用來保存節點編號的 Q.push(s); d[s]=0; vis[s]=true; while(!Q.empty()) { int x=Q.front(); Q.pop(); for(int i=0; i<G[x].size(); i++) { Edge& e=edges[G[x][i]]; if(!vis[e.to] && e.cap>e.flow) { vis[e.to]=true; d[e.to] = d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a) { if(x==t || a==0)return a; int flow=0,f;//flow用來記錄從x到t的最小殘量 for(int& i=cur[x]; i<G[x].size(); i++) { Edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to] && (f=DFS( e.to,min(a,e.cap-e.flow) ) )>0 ) { e.flow +=f; edges[G[x][i]^1].flow -=f; flow += f; a -= f; if(a==0) break; } } return flow; } int Maxflow() { int flow=0; while(BFS()) { memset(cur,0,sizeof(cur)); flow += DFS(s,INF); } return flow; } }Dinic; int main() { int n, f, a, b, c, d; scanf("%d %d %d", &n, &f, &d); int s = n * 2 + f + d + 1, t = s + 1; Dinic.init(n, s, t); for(int i = 1; i <= f; i ++) {//n * 2 - 1 ~ n * 2 + f - 1存儲從s -> 食物的邊 Dinic.AddEdge(s, n * 2 + i, 1); } for(int i = 1; i <= d; i ++) {//n * 2 + f ~ n * 2 + f + d - 1存儲從飲料 -> t的邊 Dinic.AddEdge(n * 2 + f + i, t, 1); } for(int i = 1; i <= n; i ++) { Dinic.AddEdge(i ,n + i, 1);//牛拆點以後的創建的邊1 ~ 2 * n scanf("%d %d", &a, &b); for(int j = 0; j < a; j ++) { scanf("%d", &c); Dinic.AddEdge(n * 2 + c, i, 1);//食物與牛建邊 } for(int j = 0; j < b; j ++) { scanf("%d", &c); Dinic.AddEdge(i + n, n * 2 + f + c, 1);//飲料與牛建邊 } } printf("%d\n", Dinic.Maxflow());//模版最大流? return 0; }