uva 1515 Pool construction(最大流)
来源:互联网 发布:java swing jpanel 编辑:程序博客网 时间:2024/05/19 22:58
uva 1515 Pool construction
题目大意:给一块n×m的地皮,上面有草地‘#’和洞‘.’ 。草地转换成洞需要d的费用,把洞填上种上草需要f的费用,在草地和洞之间加一道墙需要b的费用。现在问把这块n×m的地皮变成池子的最小费用是多少。(池子:边缘必须都是草地,每块草地与洞之间都有墙隔开)
解题思路:建图方式非常巧妙。先把所有边界上的洞全部变成草地,并记录费用sum。设置超级源点,连向所有边界的草地,容量为INF,然后连向其他草地,容量为d。设置超级汇点,使所有的洞,连向超级汇点,容量为f。然后地皮内每个点都与相邻的点连边,容量为b。
#######.###.#.######
超级源点向(3,3)的#连了一条边,容量为d。如果将d转换为洞的话最终答案ans + 3b - (d + b)。所以要不要对(3,3)进行转换,就变成了3b和(d + b)也就是d 和2b谁大谁小的问题。当d大于2b时,把#转换成洞是不划算的,在最大流中体现为,当d >= 2b时,(3,3)点接受了(4,3)点流入的流,(3,3)点的流量就会化为三段b的流流向(2,3)(3,2)(3,4)三个点(最大流嘛,三条边满流),就相当于在不转化(3,3)点,并在其与(2,3)(3,2)(3,4)三个点间建墙,流量 = 费用 = 3b。当d < 2b时,即使接受了(4,3)点流入的流,(3,3)点的流量还是不够流满(2,3)(3,2)(3,4)三个点,所以最后流向三个点的流量并没有3b,而是本身流量加上(4,3)点流入的流量,流量 = 费用 = d + b,也就是把(3,3)点转换为洞啦。
#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <cstdlib>using namespace std;typedef long long ll;const int PO = 105;const int N = 10005;const int M = 40005;const int INF = 0x3f3f3f3f;int n, m, s, t;int d, f, b, sum;char Gra[PO][PO];struct Dinic{ int ec, head[N], first[N], que[N], lev[N]; int Next[M], to[M], v[M]; void init() { ec = 0; memset(first, -1, sizeof(first)); } void addEdge(int a,int b,int c) { to[ec] = b; v[ec] = c; Next[ec] = first[a]; first[a] = ec++; to[ec] = a; v[ec] = 0; Next[ec] = first[b]; first[b] = ec++; } int BFS() { int kid, now, f = 0, r = 1, i; memset(lev, 0, sizeof(lev)); que[0] = s, lev[s] = 1; while (f < r) { now = que[f++]; for (i = first[now]; i != -1; i = Next[i]) { kid = to[i]; if (!lev[kid] && v[i]) { lev[kid] = lev[now] + 1; if (kid == t) return 1; que[r++] = kid; } } } return 0; } int DFS(int now, int sum) { int kid, flow, rt = 0; if (now == t || sum == 0) return sum; for (int i = head[now]; i != -1 && rt < sum; i = Next[i]) { head[now] = i; kid = to[i]; if (lev[kid] == lev[now] + 1 && v[i]) { flow = DFS(kid, min(sum - rt, v[i])); if (flow) { v[i] -= flow; v[i^1] += flow; rt += flow; } else lev[kid] = -1; } } return rt; } int dinic() { int ans = 0; while (BFS()) { for (int i = 0; i < N; i++) { head[i] = first[i]; } ans += DFS(s, INF); } return ans; } }din;void input() { sum = 0; scanf("%d %d\n", &n, &m); scanf("%d %d %d", &d, &f, &b); s = n * m + 1, t = n * m + 2; for (int i = 0; i < m; i++) { getchar(); for (int j = 0; j < n; j++) { scanf("%c", &Gra[i][j]); if ((i == 0 || j == 0 || i == m - 1 || j == n - 1) && Gra[i][j] == '.') { Gra[i][j] = '#'; sum += f; } } }}void build() { for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (i != 0) din.addEdge(i * n + j, (i - 1) * n + j, b); if (j != 0) din.addEdge(i * n + j, i * n + j - 1, b); if (i != m - 1) din.addEdge(i * n + j, (i + 1) * n + j, b); if (j != n - 1) din.addEdge(i * n + j, i * n + j + 1, b); } } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (i == 0 || j == 0 || i == m - 1 || j == n - 1) din.addEdge(s, i * n + j, INF); else if (Gra[i][j] == '#') din.addEdge(s, i * n + j, d); else din.addEdge(i * n + j, t, f); } }}int main() { int T; scanf("%d", &T); while (T--) { din.init(); input(); build(); printf("%d\n", sum + din.dinic()); } return 0;}
0 0
- uva 1515 Pool construction(最大流)
- UVA 1515 Pool construction(网络流)
- Uva-1515-Pool construction
- UVa 1515 Pool construction
- UVA 1515 Pool construction
- UVA 1515Pool construction
- UVA 1515 Pool construction
- 1515 - Pool construction(最大流最小割模型)
- UVA 1515 Pool construction(最小割)
- uva 1515 Pool construction(最小割)
- 最小割 UVA 1515 Pool construction
- UVA 1515 Pool construction [最小割]
- LA 5905 Pool construction 最大流
- [最小割最大流]UVa1515 - Pool construction
- 1515 - Pool construction
- 【网络流】- LA5905-Pool construction
- uva 10720 Graph Construction()
- UVa 10720 - Graph Construction
- One day
- js 取模 取余
- 树形DP+树的最大独立集+无根树转化有根树 模板
- 新浪微博 OAuth2.0 授权认证
- 华硕笔记本U盘启动设置
- uva 1515 Pool construction(最大流)
- Ubuntu 查看文件以及磁盘空间大小管理
- JUCE中的deleteatshutdown
- PHP开发app接口(2)
- Docker1.8.1安装
- FilenameFilter与FileFilter的区别
- 了解Android四大基本组件
- PAT(B) 1020. 月饼
- NOIP2014寻找道路