HDU 3879 Base Station(最大权闭合)
2015-09-04 15:36
393 查看
题目大意:给出N个站的修建花费和M条收益边,问如何建站才能使收益达到最大化
解题思路:最大权闭合,点和边分成两个点集,边和源点相连,权值为收益
点和汇点相连,权值为建造该点的花费
点和边如果有关系的话,就连边,权值为INF
具体证明的话,详见胡伯涛的最小割在信息竞赛中的应用
ISAP解法:
Dinic解法:
解题思路:最大权闭合,点和边分成两个点集,边和源点相连,权值为收益
点和汇点相连,权值为建造该点的花费
点和边如果有关系的话,就连边,权值为INF
具体证明的话,详见胡伯涛的最小割在信息竞赛中的应用
ISAP解法:
[code]#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std; const int MAXNODE = 55010; const int MAXEDGE = 400000; typedef int Type; const Type INF = 0x3f3f3f3f; struct Edge { int u, v, next; Type cap, flow; Edge() {} Edge(int u, int v, Type cap, Type flow, int next) { this->u = u; this->v = v; this->cap = cap; this->flow = flow; this->next= next; } }; struct ISAP { int n, m, s, t; Edge edges[MAXEDGE]; int head[MAXNODE], p[MAXNODE], num[MAXNODE], cur[MAXNODE], d[MAXNODE]; bool vis[MAXNODE]; void init(int n) { this->n = n; memset(head, -1, sizeof(head)); m = 0; } void AddEdge(int u, int v, Type cap) { edges[m] = Edge(u, v, cap, 0, head[u]); head[u] = m++; edges[m] = Edge(v, u, 0, 0, head[v]); head[v] = m++; } bool BFS() { memset(vis, 0, sizeof(vis)); queue<int> Q; for (int i = 0; i < n; i++) d[i] = INF; d[t] = 0; vis[t] = 1; Q.push(t); while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = head[u]; ~i; i = edges[i].next) { Edge &e = edges[i ^ 1]; if (!vis[e.u] && e.cap > e.flow) { vis[e.u] = true; d[e.u] = d[u] + 1; Q.push(e.u); } } } return vis[s]; } Type Augment() { int u = t; Type flow = INF; while (u != s) { Edge &e = edges[p[u]]; flow = min(flow, e.cap - e.flow); u = edges[p[u]].u; } u = t; while (u != s) { edges[p[u]].flow += flow; edges[p[u] ^ 1].flow -= flow; u = edges[p[u]].u; } return flow; } Type Maxflow(int s, int t) { this->s = s; this->t = t; Type flow = 0; BFS(); //如果s-->t走不通 if (d[s] >= n) return 0; memset(num, 0, sizeof(num)); for (int i = 0; i < n; i++) cur[i] = head[i]; for (int i = 0; i < n; i++) if (d[i] < INF) num[d[i]]++; int u = s; while (d[s] < n) { if (u == t) { flow += Augment(); u = s; } bool ok = false;//纪录是否找到了下一个点 for (int i = cur[u]; ~i; i = edges[i].next) { Edge &e = edges[i]; if (e.cap > e.flow && d[u] == d[e.v] + 1) { ok = true; p[e.v] = i;//点v由第i条边增广得到 cur[u] = i;//尝试到第i条边 u = e.v; break; } } //如果没找到下一个点,表示u到t的最短路要变长了,或者没路可走了 if (!ok) { //找寻u到下一个点的最短路 int Min = n - 1; for (int i = head[u]; ~i; i = edges[i].next) { Edge &e = edges[i]; if (e.cap > e.flow) Min = min(Min, d[e.v]); } if (--num[d[u]] == 0)//GAP优化 break; num[d[u] = Min + 1]++; cur[u] = head[u]; //返回前一个点,因为该点的最短距离已经变了 if (u != s) u = edges[p[u]].u; } } return flow; } }isap; int n, m; void init (){ int source = 0, sink = n + m + 1; int SumProfit = 0, SumCost = 0 ; isap.init(sink + 1); int u, v, c; for (int i = 1; i <= n; i++) { scanf("%d", &c); isap.AddEdge(i, sink, c); SumCost += c; } for (int i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &c); SumProfit += c; isap.AddEdge(source, n + i, c); isap.AddEdge(n + i, u, INF); isap.AddEdge(n + i, v, INF); } isap.AddEdge(n + m + 2, source, SumProfit); isap.AddEdge(sink, n + m + 3, SumCost); printf("%d\n", SumProfit - isap.Maxflow(n + m + 2, n + m + 3)); } int main() { while (scanf("%d%d", &n, &m) != EOF ) { init(); } return 0; }
Dinic解法:
[code]#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std; const int MAXNODE = 60000; const int MAXEDGE = 400000; typedef int Type; const Type INF = 0x3f3f3f3f; struct Edge{ int u, v, next; Type cap, flow; Edge() {} Edge(int u, int v, Type cap, Type flow, int next) : u(u), v(v), cap(cap), flow(flow), next(next){} }; struct Dinic{ int n, m, s, t; Edge edges[MAXEDGE]; int head[MAXNODE]; int cur[MAXNODE]; bool vis[MAXNODE]; Type d[MAXNODE]; vector<int> cut; void init(int n) { this->n = n; memset(head, -1, sizeof(head)); m = 0; } void AddEdge(int u, int v, Type cap) { edges[m] = Edge(u, v, cap, 0, head[u]); head[u] = m++; edges[m] = Edge(v, u, 0, 0, head[v]); head[v] = m++; } bool BFS() { memset(vis, 0, sizeof(vis)); queue<int> Q; Q.push(s); d[s] = 0; vis[s] = 1; while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = head[u]; i != -1; i = edges[i].next) { Edge &e = edges[i]; if (!vis[e.v] && e.cap > e.flow) { vis[e.v] = true; d[e.v] = d[u] + 1; Q.push(e.v); } } } return vis[t]; } Type DFS(int u, Type a) { if (u == t || a == 0) return a; Type flow = 0, f; for (int &i = cur[u]; i != -1; i = edges[i].next) { Edge &e = edges[i]; if (d[u] + 1 == d[e.v] && (f = DFS(e.v, min(a, e.cap - e.flow))) > 0) { e.flow += f; edges[i ^ 1].flow -= f; flow += f; a -= f; if (a == 0) break; } } return flow; } Type Maxflow(int s, int t) { this->s = s; this->t = t; Type flow = 0; while (BFS()) { for (int i = 0; i < n; i++) cur[i] = head[i]; flow += DFS(s, INF); } return flow; } void Mincut() { cut.clear(); for (int i = 0; i < m; i += 2) { if (vis[edges[i].u] && !vis[edges[i].v]) cut.push_back(i); } } }dinic; int n, m; void init() { int source = 0, sink = n + m + 1; dinic.init(sink + 1); int Sum = 0; int u, v, c; for (int i = 1; i <= n; i++) { scanf("%d", &c); dinic.AddEdge(m + i, sink, c); } for (int i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &c); dinic.AddEdge(source, i, c); dinic.AddEdge(i, v + m, INF); dinic.AddEdge(i, u + m, INF); Sum += c; } int maxflow = dinic.Maxflow(source, sink); printf("%d\n", Sum - maxflow); } int main() { while (scanf("%d%d", &n, &m) == 2) { init(); } return 0; }
相关文章推荐
- php这是一个随机打印输出字符串的例子
- NotePad大小写转换
- iOS 在UILabel显示不同的字体和颜色
- UVa 714 Copying Books (最大值尽量小_二分+贪心)
- 2015
- Git学习笔记
- 剑指offer:从尾到头打印链表
- 认识自己
- Exception starting filter struts2|java.lang.ClassNotFoundException
- Eclipse中开启java的assert选项
- hdu4291A Short problem 矩阵快速幂
- 3D游戏与计算机图形学中的数学方法-四元数
- PWM设计
- 1060. Are They Equal (25)
- mysql嵌套关联查询
- 最长公共子序列
- Java 内存管理 堆和栈 GC 垃圾回收 Garbage Collection
- Stack - Simplify Path
- REST 资源分析法
- swift 解析json数据