POJ-3281 Dining(最大流)(拆點)
阿新 • • 發佈:2020-07-14
題意:牧場主為N只牛(1 <= N <= 100)準備了a(1 <= a <= 100)種可以吃的和b(1 <= b <= 100)種可以喝的。每隻牛的克隆體都有各自喜歡的食物和飲料,而每種食物或飲料只能分配給一隻牛,最多有多少隻牛可以同時得到喜歡的食物和飲料?
分析:一隻牛隻要獲得它的喜歡清單中的一種食物和一種飲料就滿足了,求最大的牛的數量。我們一種直觀的想法是\(源---食物---牛---飲料---匯點\),但是這樣會有一個如下的問題。
就是,從源頭提供的食物會經過綠色的邊分叉,這樣一隻牛可以攜帶多份食物到達終點,我們可以把一隻牛拆成兩點,在中間加一條\(容量為1\)
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int inf = 1 << 29, N = 50005, M = 300005; int h[N], e[M], ne[M], d[N]; int w[M]; int m, s, t, idx, maxflow; //n只牛,a種吃的,b種喝的 int n, a, b; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; e[idx] = a, w[idx] = 0, ne[idx] = h[b], h[b] = idx++; } //構造分層圖 bool bfs() { memset(d, 0, sizeof d); queue<int> q; q.push(s), d[s] = 1; while (q.size()) { int u = q.front(); q.pop(); for (int i = h[u]; i != -1; i = ne[i]) { int j = e[i]; if (w[i] && !d[j]) { q.push(j); d[j] = d[u] + 1; if (j == t) return true; } } } return false; } //在分層圖上增廣 int dinic(int u, int flow) { if (u == t) return flow; int rest = flow, k; for (int i = h[u]; i != -1 && rest; i = ne[i]) { int j = e[i]; if (w[i] && d[j] == d[u] + 1) { k = dinic(j, min(rest, w[i])); //增廣完畢 if (!k) d[j] = 0; w[i] -= k; w[i ^ 1] += k; //剩餘容量 rest -= k; } } //返回流過的值 return flow - rest; } int main() { scanf("%d%d%d", &n, &a, &b); memset(h, -1, sizeof h); s = 0, t = a + n + n + b + 1; for (int i = 1; i <= n; ++i) { int f, d; scanf("%d%d", &f, &d); int u; for (int j = 1; j <= f; ++j) { scanf("%d", &u); add(u, a + i, 1); } for (int j = 1; j <= d; ++j) { scanf("%d", &u); add(a + n + i, a + n + n + u, 1); } add(a + i, a + n + i, 1); } for (int i = 1; i <= a; ++i) { add(0, i, 1); } for (int i = 1; i <= b; ++i) { add(a + n + n + i, t, 1); } int flow = 0; while (bfs()) { while (flow = dinic(s, inf)) maxflow += flow; } printf("%d\n", maxflow); return 0; }