poj 3281 Dining 最大流
2016-03-16 10:49
381 查看
题目
题目链接:http://poj.org/problem?id=3281题目来源:《挑战》例题。
简要题意:一些牛有喜欢的饮料和食物,问最多多少牛可以拿到喜欢的饮料和食物。
题解
再次证明图论是多么神奇。整个图分为66层。
第一层为源点,向所有食物连出一条流量为11的边。
第二层为食物,向喜欢它的牛的入点连出一条流量为11的边。
第三层为牛的入点,向牛的出点连出一条流量为11边。
第四层为牛的出点,向牛喜欢的饮料连出一条流量为11的边。
第五层为饮料,向会点连出一条流量为11的边。
第六层为汇点。
可以看出本来牛是一个点的,但是由于在点上有个流量限制所以分成两个点。
整个东西的最大流就是结果了,约束条件都融入到了图中,每个食物只能使用一遍,每个食物对应一头牛,每头牛只能选取一次,对应一种饮料。
也可以看成是两组匹配,然后中间的牛拆分成两个点。
本来是写的Ford-Fulkerson的,然后初始化规模弄错了,一直TLE,改了Dinic还T,后来就发现了。
Ford-Fulkerson代码
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <stack> #include <queue> #include <string> #include <vector> #include <set> #include <map> #define fi first #define se second using namespace std; typedef long long LL; typedef pair<int,int> PII; // head const int N = 105; const int M = N * N * N * 2; struct Edge { int to, nxt, cap, rev; Edge(int to, int nxt, int cap, int rev) : to(to), nxt(nxt), cap(cap), rev(rev) {} Edge() {} }; int head[N*4]; Edge e[M]; void addEdge(int from, int to, int cap, int rev, int cnt) { e[cnt] = Edge(to, head[from], cap, rev); head[from] = cnt; } void addEdgePair(int from, int to, int cap, int &cnt) { addEdge(from, to, cap, cnt+1, cnt); addEdge(to, from, 0, cnt, cnt+1); cnt += 2; } void init(int n) { for (int i = 0; i <= n; i++) head[i] = -1; } bool vis[N*4]; int dfs(int x, int en, int flow) { if (x == en) return flow; vis[x] = true; for (int i = head[x]; ~i; i = e[i].nxt) { int to = e[i].to, rev = e[i].rev; if (!vis[to] && e[i].cap > 0) { int f = dfs(to, en, min(flow, e[i].cap)); if (f > 0) { e[i].cap -= f; e[rev].cap += f; return f; } } } return 0; } int maxFlow(int st, int en) { int flow = 0; while (true) { memset(vis, 0, sizeof vis); if (!dfs(st, en, 1e9)) break; flow++; } return flow; } int main() { int n, f, d, fn, dn, x; while (scanf("%d%d%d", &n, &f, &d) == 3) { int ec = 0, st = 2 * n + f + d, en = st + 1; init(en); for (int i = 0; i < f; i++) { addEdgePair(st, 2 * n + i, 1, ec); } for (int i = 0; i < d; i++) { addEdgePair(2 * n + f + i, en, 1, ec); } for (int i = 0; i < n; i++) { addEdgePair(i, n + i, 1, ec); scanf("%d%d", &fn, &dn); for (int j = 0; j < fn; j++) { scanf("%d", &x); x--; addEdgePair(2 * n + x, i, 1, ec); } for (int j = 0; j < dn; j++) { scanf("%d", &x); x--; addEdgePair(n + i, 2 * n + f + x, 1, ec); } } printf("%d\n", maxFlow(st, en)); } return 0; }
Dinic代码
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <stack> #include <queue> #include <string> #include <vector> #include <set> #include <map> #define fi first #define se second using namespace std; typedef long long LL; typedef pair<int,int> PII; // head const int N = 105; const int M = N * N * N * 2; struct Edge { int to, nxt, cap, rev; Edge(int to, int nxt, int cap, int rev) : to(to), nxt(nxt), cap(cap), rev(rev) {} Edge() {} }; int head[N*4]; Edge e[M]; void addEdge(int from, int to, int cap, int rev, int cnt) { e[cnt] = Edge(to, head[from], cap, rev); head[from] = cnt; } void addEdgePair(int from, int to, int cap, int &cnt) { addEdge(from, to, cap, cnt+1, cnt); addEdge(to, from, 0, cnt, cnt+1); cnt += 2; } void init(int n) { for (int i = 0; i <= n; i++) head[i] = -1; } int level[N*4]; int iter[N*4]; bool bfs(int st, int en) { level[st] = 0; queue<int> q; q.push(st); while (!q.empty()) { int cur = q.front(); q.pop(); for (int i = head[cur]; ~i; i = e[i].nxt) { int to = e[i].to; if (level[to] == -1 && e[i].cap > 0) { q.push(to); level[to] = level[cur] + 1; } } } } int dfs(int x, int en, int flow) { if (x == en) return flow; for (int &i = iter[x]; ~i; i = e[i].nxt) { int to = e[i].to, rev = e[i].rev; if (e[i].cap == 0 || level[to] <= level[x]) continue; int f = dfs(to, en, min(flow, e[i].cap)); if (f > 0) { e[i].cap -= f; e[rev].cap += f; return f; } } return 0; } int maxFlow(int st, int en) { int flow = 0; while (true) { memset(level, -1, sizeof level); bfs(st, en); memcpy(iter, head, sizeof iter); if (level[en] == -1) break; while (dfs(st, en, 1)) { flow++; } } return flow; } int main() { int n, f, d, fn, dn, x; while (scanf("%d%d%d", &n, &f, &d) == 3) { init(2 * n + d + f + 2); int ec = 0; int st = 2 * n + f + d, en = st + 1; int bef = 2 * n, bed = 2 * n + f; for (int i = 0; i < f; i++) { addEdgePair(st, bef + i, 1, ec); } for (int i = 0; i < d; i++) { addEdgePair(bed + i, en, 1, ec); } for (int i = 0; i < n; i++) { addEdgePair(i, n + i, 1, ec); scanf("%d%d", &fn, &dn); for (int j = 0; j < fn; j++) { scanf("%d", &x); x--; addEdgePair(bef + x, i, 1, ec); } for (int j = 0; j < dn; j++) { scanf("%d", &x); x--; addEdgePair(n + i, bed + x, 1, ec); } } printf("%d\n", maxFlow(st, en)); } return 0; }
相关文章推荐
- [平常积累]
- iOS开发之应用首次启动显示用户引导
- Ubuntu下MTP设备的挂载目录
- C/C++ const 关键字详解
- 同步与异步、阻塞与非阻塞
- 分页
- 实验总结
- Socket 超时设置
- 使用 LINQPad 将linq转换为 lambda表达式 或者 SQL语句
- 以人致胜 SAP开启HR云端变革之旅
- echo体验报告(附音乐行业分析)
- Android标题栏各种设置
- tomcat8目录结构
- bash alias 终极使用方法
- 百度地图js根据经纬度定位和拖动定位点
- supervisor
- (转)Tomcat内存设置详解
- ContentValues
- java 删除LinkedList链表中的结点(只给出一个结点)
- lightoj 1033 - Generating Palindromes LCSor区间DP