【最大流】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
",dinic());
87     return 0;
88 }

END

原文地址:https://www.cnblogs.com/antiquality/p/10351733.html