// [5/29/2014 Sjm] /* 对于此题仍属于最大流 多个源点,多个汇点 的题型,不过技巧性增加了。。。 第一想法: 建图方式为: 超级源点 --> 食物 --> 牛 --> 饮料 --> 超级汇点 (注每条连线的容量为 1) 但不幸的是,wa。。。 // 要注意: 1) Each cow has a preference for certain foods and drinks, and she will consume no others. 2) 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). 这意味着每头牛只能连接一个食物、一个饮料,且被连接的食物和饮料不能被其他牛连接。 // 而像上面的方法建图,食物流向食物相对应的牛的流量可以 >1, 导致由牛流出的流量 >1, 使一头牛可连接多个饮料。。。 看到一种很厉害的解决办法,将牛一分为二: 超级源点 --> 食物 --> 牛a --> 牛b --> 饮料 --> 超级汇点 (注每条连线的容量为 1) 将一头牛一分为二后,由于牛a和牛b之间的连线的容量为 1,,故而 尽管由食物可以流向牛a的流量 >1 ,但在由牛b流向饮料的流量被限制为了 1,解决了上面问题。 */#include <iostream> #include <cstdlib> #include <cstdio> #include <vector> #include <algorithm> #include <cstring> using namespace std; const int MAX_V = 410; const int INF = 0x3f3f3f3f; int N, F, D; struct edge{ int to, cap, rev; }; vector<edge> G[MAX_V]; bool used[MAX_V]; void Add_edge(int from, int to, int cap) { edge e1 = { to, cap, G[to].size() }; G[from].push_back(e1); edge e2 = { from, 0, G[from].size() - 1 }; G[to].push_back(e2); } int Dfs(int v, int t, int f) { if (v == t) return f; used[v] = true; for (int i = 0; i < G[v].size(); i++) { edge &e = G[v][i]; if (!used[e.to] && e.cap > 0) { int d = Dfs(e.to, t, min(f, e.cap)); if (d > 0) { e.cap -= d; G[e.to][e.rev].cap += d; return d; } } } return 0; } int Max_flow(int s, int t) { int flow = 0; for (;;) { memset(used, 0, sizeof(used)); int f = Dfs(s, t, INF); if (!f) { return flow; } flow += f; } } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); while (~scanf("%d %d %d", &N, &F, &D)) { int f_num, d_num; for (int i = 1; i <= N; i++) { Add_edge(i, N + i, 1); // 将 牛 一分为二 scanf("%d %d", &f_num, &d_num); int t_f, t_d; for (int j = 1; j <= f_num; j++) { scanf("%d", &t_f); Add_edge(2 * N + t_f, i, 1); // 食物 --> 食物相对应的牛 } for (int k = 1; k <= d_num; k++) { scanf("%d", &t_d); Add_edge(N + i, 2 * N + F + t_d, 1); // 牛 --> 牛相对应的饮料 } } for (int i = 2 * N + 1; i <= 2 * N + F; i++) { Add_edge(0, i, 1); // 超级源点 --> 每一种食物 } for (int i = 2 * N + F + 1; i <= 2 * N + F + D; i++) { Add_edge(i, 2 * N + F + D + 1, 1); // 每一种饮料 --> 超级汇点 } printf("%d\n", Max_flow(0, 2 * N + F + D + 1)); for (int i = 0; i <= 2 * N + F + D + 1; i++) { G[i].clear(); } } return 0; }
最大流(多个源点,多个汇点) 之 poj 3281
最新推荐文章于 2022-09-09 15:08:56 发布