POJ 3281:Dining(最大流)

http://poj.org/problem?id=3281

题意:有n头牛,f种食物,d种饮料,每头牛有fnum种喜欢的食物,dnum种喜欢的饮料,每种食物如果给一头牛吃了,那么另一个牛就不能吃这种食物了,饮料也同理,问最多有多少头牛可以吃到它喜欢的饮料和食物。

思路:一开始还以为二分匹配可以做,当然如果只有食物或者饮料其中一种就可以做。难点在于建图。看了下书,因为要保证经过牛的流量是1(每种食物对应分配给一头牛,每种饮料对应分配给一头牛,避免一头牛吃多份),所以要把牛拆成两个点。形成这样的路径S->f->cow1->cow2->d->T。

算法思想大概是通过BFS构造出分层图,然后通过DFS找增广路更新边流量和最大流的信息。

转的图。

 2 #include <cstring>
 3 #include <vector>
 4 #include <queue>
 5 using namespace std;
 6 #define N 410
 7 #define INF 0x3f3f3f3f
 8 struct Edge {
 9     int u, v, cap;
10     Edge () {}
11     Edge (int u, int v, int cap) : u(u), v(v), cap(cap) {}
12 }edge[N*N];
13 vector<int> G[N];
14 int tot, S, T, dis[N], cur[N];
15 
16 void AddEdge(int u, int v, int c) {
17     G[u].push_back(tot);
18     edge[tot++] = Edge(u, v, c);
19     G[v].push_back(tot);
20     edge[tot++] = Edge(v, u, 0); // 反向弧的流量是0
21 }
22 
23 int BFS() {
24     queue<int> que;
25     que.push(S);
26     memset(dis, INF, sizeof(dis));
27     dis[S] = 0;
28     while(!que.empty()) {
29         int u = que.front(); que.pop();
30         for(int i = 0; i < G[u].size(); i++) {
31             Edge &e = edge[G[u][i]];
32             if(e.cap > 0 && dis[e.v] == INF) {
33                 dis[e.v] = dis[u] + 1;
34                 que.push(e.v);
35             }
36         }
37     }
38     return dis[T] < INF;
39 }
40 
41 int DFS(int u, int maxflow) {
42     if(u == T) return maxflow;
43     for(int i = cur[u]; i < G[u].size(); i++) {
44         cur[u] = i;
45         Edge &e = edge[G[u][i]];
46         if(dis[e.v] == dis[u] + 1 && e.cap > 0) {
47             int flow = DFS(e.v, min(maxflow, e.cap));
48             if(flow) {
49                 e.cap -= flow;
50                 edge[G[u][i]^1].cap += flow;
51                 return flow;
52             }
53         }
54     }
55     return 0;
56 }
57 
58 int Dinic() {
59     int ans = 0, flow;
60     while(BFS()) {
61 //        puts("BFS");
62         memset(cur, 0, sizeof(cur));
63         while(flow = DFS(S, INF)) ans += flow;
64     }
65     return ans;
66 }
67 
68 int main() {
69     int n, f, d;
70     while(~scanf("%d%d%d", &n, &f, &d)) {
71         S = 0, T = 2 * n + f + d + 1, tot = 0;
72         for(int i = 0; i <= T; i++) G[i].clear();
73         for(int i = 1; i <= f; i++)
74             AddEdge(S, 2 * n + i, 1); // 源点到食物
75         for(int i = 1; i <= d; i++)
76             AddEdge(2 * n + f + i, T, 1); // 饮料到汇点
77         for(int i = 1; i <= n; i++) {
78             int fnum, dnum;
79             scanf("%d%d", &fnum, &dnum);
80             AddEdge(i, n + i, 1); // 每只牛拆点
81             for(int j = 1; j <= fnum; j++) {
82                 int v; scanf("%d", &v);
83                 AddEdge(2 * n + v, i, 1); // 食物到牛的第一个点
84             }
85             for(int j = 1; j <= dnum; j++) {
86                 int v; scanf("%d", &v);
87                 AddEdge(n + i, 2 * n + f + v, 1); // 牛的第二个点到饮料
88             }
89         }
90         int ans = Dinic();
91         printf("%d
", ans);
92     }
93     return 0;
94 }
原文地址:https://www.cnblogs.com/fightfordream/p/6206144.html