HDU 3879:Base Station(最大权闭合图)
Posted Shadowdsp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 3879:Base Station(最大权闭合图)相关的知识,希望对你有一定的参考价值。
http://acm.hdu.edu.cn/showproblem.php?pid=3879
http://www.lydsy.com/JudgeOnline/problem.php?id=1497
题意:给出n个点m条边,其中每个点有一个权值代表修建这个点需要耗费的钱,然后m条边里面,代表如果两个修建好的点相连的话,那么可以得到一点利润。求最大的获利。
思路:和BZOJ 1497是同一道题目。学习最大权闭合图的题目,看了一下不清楚应该怎么建图,然后只好搜一个论文来看看。http://wenku.baidu.com/view/6507a6fe2cc58bd63186bdaf.html
建图:将S与n个点相连,权值为点权,将m条边当成点与T相连,权值为边权,边的两个顶点分别再和化成点的边相连,权值为INF。
闭合图可以解决一些依赖关系,例如这道题目需要有两个顶点才可以得到一条边,边是依赖于两个顶点的形成的。
于是网络是这样的:S->站的点->边的点->T。
我们对这个网络得到的一个割 = 选择的站的花费 + 未选择的边的利润(也可以看作损失的利润),显然这个割集越小越好,即最小割。我们要求的是答案 = 选择的边的利润 - 选择的站的利润。
那么我们一开始可以先累加得到一个选择所有边的利润tot,那么恰好tot - 最小割 = 选择所有边的利润 - 未选择边的利润 - 选择的站的花费 = 选择的边的利润 - 选择的站的利润 = 答案。
所以跑一遍最大流后就用tot - 最大流就可以得到答案了。
记得边的数组要开大一点。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 using namespace std; 6 #define INF 0x3f3f3f3f 7 #define N 60010 8 #define M 350010 // 30w不过 9 struct Edge { 10 int u, v, nxt, cap; 11 Edge () {} 12 Edge (int u, int v, int nxt, int cap) : u(u), v(v), nxt(nxt), cap(cap) {} 13 } edge[M]; 14 int head[N], tot, S, T, cur[N], dis[N], gap[N], pre[N]; 15 16 void Add(int u, int v, int cap) { 17 edge[tot] = Edge(u, v, head[u], cap); head[u] = tot++; 18 edge[tot] = Edge(v, u, head[v], 0); head[v] = tot++; 19 } 20 21 void BFS() { 22 queue<int> que; 23 que.push(T); 24 memset(dis, INF, sizeof(dis)); 25 memset(gap, 0, sizeof(gap)); 26 gap[0]++; dis[T] = 0; 27 while(!que.empty()) { 28 int u = que.front(); que.pop(); 29 for(int i = head[u]; ~i; i = edge[i].nxt) { 30 if(dis[edge[i].v] != INF) continue; 31 dis[edge[i].v] = dis[u] + 1; 32 gap[dis[edge[i].v]]++; 33 que.push(edge[i].v); 34 } 35 } 36 } 37 38 int ISAP(int n) { 39 BFS(); 40 memcpy(cur, head, sizeof(cur)); 41 int u = pre[S] = S, flow, ans = 0, index, i; 42 while(dis[S] < n) { 43 if(u == T) { 44 flow = INF; 45 for(i = S; i != T; i = edge[cur[i]].v) 46 if(flow > edge[cur[i]].cap) flow = edge[cur[i]].cap, index = i; 47 for(i = S; i != T; i = edge[cur[i]].v) 48 edge[cur[i]].cap -= flow, edge[cur[i]^1].cap += flow; 49 u = index; ans += flow; 50 } 51 for(i = cur[u]; ~i; i = edge[i].nxt) if(edge[i].cap && dis[edge[i].v] + 1 == dis[u]) break; 52 if(~i) { cur[u] = i; pre[edge[i].v] = u; u = edge[i].v; } 53 else { 54 if(--gap[dis[u]] == 0) break; 55 int md = n + 1; 56 for(i = head[u]; ~i; i = edge[i].nxt) 57 if(edge[i].cap && dis[edge[i].v] < md) md = dis[edge[i].v], cur[u] = i; 58 gap[dis[u] = md + 1]++; 59 u = pre[u]; 60 } 61 } 62 return ans; 63 } 64 65 int main() { 66 int n, m; 67 while(~scanf("%d%d", &n, &m)) { 68 memset(head, -1, sizeof(head)); 69 tot = 0; S = 0; T = n + m + 1; 70 for(int i = 1; i <= n; i++) { 71 int w; scanf("%d", &w); 72 Add(S, i, w); // 源点和站点相连 73 } 74 int tot = 0; 75 for(int i = 1; i <= m; i++) { 76 int a, b, c; 77 scanf("%d%d%d",&a, &b, &c); 78 tot += c; // 选择边的利润和 79 Add(i + n, T, c); // 边的点和汇点相连 80 Add(a, i + n, INF); 81 Add(b, i + n, INF); 82 } 83 printf("%d\n", tot - ISAP(T + 1)); 84 } 85 return 0; 86 }
以上是关于HDU 3879:Base Station(最大权闭合图)的主要内容,如果未能解决你的问题,请参考以下文章
hdu2255 奔小康赚大钱 km算法解决最优匹配(最大权完美匹配)
hdu 1569 &1565 (二分图带权最大独立集 - 最小割应用)