【最大流】bzoj1711: [Usaco2007 Open]Dining吃饭
正在网络流入门(原来这种题用网络流做)
Description
农夫JOHN为牛们做了很好的食品,但是牛吃饭很挑食. 每一头牛只喜欢吃一些食品和饮料而别的一概不吃.虽然他不一定能把所有牛喂饱,他还是想让尽可能多的牛吃到他们喜欢的食品和饮料. 农夫JOHN做了F (1 <= F <= 100) 种食品并准备了D (1 <= D <= 100) 种饮料. 他的N ( 1 <= N <= 100)头牛都以决定了是否愿意吃某种食物和喝某种饮料. 农夫JOHN想给每一头牛一种食品和一种饮料,使得尽可能多的牛得到喜欢的食物和饮料. 每一件食物和饮料只能由一头牛来用. 例如如果食物2被一头牛吃掉了,没有别的牛能吃食物2.
Input
* 第一行: 三个数: N, F, 和 D
* 第2..N+1行: 每一行由两个数开始F_i 和D_i, 分别是第i 头牛可以吃的食品数和可以喝的饮料数.下F_i个整数是第i头牛可以吃的食品号,再下面的D_i个整数是第i头牛可以喝的饮料号码.
Output
* 第一行: 一个整数,最多可以喂饱的牛数.
题目分析
首先将源点连向所有食物;所有饮料连向汇点。接下来是中间奶牛的部分,容易发现如果简单地食物-奶牛-饮料一连,将会导致一头奶牛可能吃了很多饮料食物。这里有一种巧妙的处理方法:将一头奶牛拆成两个点,中间连一条容量为1的边,意味着一头牛只能占有一个食物/饮料。
话说这题在bzoj为什么会莫名其妙TLE啊……
1 #include<bits/stdc++.h> 2 const int maxn = 1035; 3 const int maxm = 10035; 4 const int INF = 2e9; 5 6 struct Edge 7 { 8 int u,v,f,c; 9 Edge(int a=0, int b=0, int c=0, int d=0):u(a),v(b),f(c),c(d) {} 10 }edges[maxm]; 11 int n,f,d,S,T,lv[maxn]; 12 int edgeTot,head[maxn],nxt[maxm]; 13 14 int read() 15 { 16 char ch = getchar(); 17 int num = 0, fl = 1; 18 for (; !isdigit(ch); ch = getchar()) 19 if (ch=='-') fl = -1; 20 for (; isdigit(ch); ch = getchar()) 21 num = (num<<1)+(num<<3)+ch-48; 22 return num*fl; 23 } 24 void addedge(int u, int v, int c) 25 { 26 edges[edgeTot] = Edge(u, v, 0, c), nxt[edgeTot] = head[u], head[u] = edgeTot++; 27 edges[edgeTot] = Edge(v, u, 0, 0), nxt[edgeTot] = head[v], head[v] = edgeTot++; 28 } 29 bool buildLevel() 30 { 31 memset(lv, 0, sizeof lv); 32 std::queue<int> q; 33 q.push(S), lv[S] = 1; 34 for (int tmp; q.size(); ) 35 { 36 tmp = q.front(), q.pop(); 37 for (int i=head[tmp]; i!=-1; i=nxt[i]) 38 { 39 int v = edges[i].v; 40 if (!lv[v]&&edges[i].f < edges[i].c){ 41 lv[v] = lv[tmp]+1, q.push(v); 42 if (v==T) return true; 43 } 44 } 45 } 46 return false; 47 } 48 int fndPath(int x, int lim) 49 { 50 if (x==T) return lim; 51 for (int i=head[x]; i!=-1; i=nxt[i]) 52 { 53 int v = edges[i].v, val; 54 if (lv[x]+1==lv[v]&&edges[i].f < edges[i].c){ 55 if ((val = fndPath(v, std::min(lim, edges[i].c-edges[i].f)))){ 56 edges[i].f += val, edges[i^1].f -= val; 57 return val; 58 }else lv[v] = -1; 59 } 60 } 61 return 0; 62 } 63 int dinic() 64 { 65 int ret = 0, val; 66 while (buildLevel()) 67 while ((val = fndPath(S, INF))) ret += val; 68 return ret; 69 } 70 int main() 71 { 72 memset(head, -1, sizeof head); 73 n = read(), f = read(), d = read(); 74 S = 0, T = n*2+f+d+1; 75 for (int i=1; i<=n; i++) 76 { 77 int k1 = read(), k2 = read(); 78 for (; k1; --k1) 79 addedge(read(), f+i, 1); 80 for (; k2; --k2) 81 addedge(f+i+n, read()+n*2+f, 1); 82 addedge(f+i, f+i+n, 1); 83 } 84 for (int i=1; i<=f; i++) addedge(S, i, 1); 85 for (int i=1; i<=d; i++) addedge(f+2*n+i, T, 1); 86 printf("%d\n",dinic()); 87 return 0; 88 }
END