最大权闭合图
Posted chiarochinoful
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最大权闭合图相关的知识,希望对你有一定的参考价值。
前置芝士:最大流最小割
一. 啥是闭合图
一件事件x发生需要一个条件:
1. y事件已经发生
2. z事件已经发生
对于这样的依赖关系 , 我们可以用闭合来来描述或者解决
有向图的闭合图(closure)(来源于 胡伯涛《最小割模型在信息学竞赛中的应用》 论文 )
物理意义:事物间依赖关系:一个事件要发生 , 她需要的所有前提也都一定发生
最大权闭合图是点权最大的闭合图
一道求最大权闭合图的题
构图:
建源点S, 汇点T
将源点S与正权点连边 , 容量是点权
将汇点T与负权点连边 , 容量是点权
将题目描述的边连上 , 容量是无限大
解决:
闭合图的权为所有正权点减去该图中割的容量
那么 , 很显然割越小答案越大
所以就要去求最小鸽 , 也就是最大流
这样 , 那道NOI题也就好做了
1 #include<cstdio> 2 #include<queue> 3 #include<cstring> 4 #include<cstdlib> 5 #include<iostream> 6 #include<algorithm> 7 #define APART puts("----------------------") 8 #define debug 1 9 #define FILETEST 0 10 #define inf 120010 11 #define ll long long 12 #define ha 998244353 13 #define INF 0x7fffffff 14 #define INF_T 9223372036854775807 15 #define DEBUG printf("%s %d\\n",__FUNCTION__,__LINE__) 16 17 namespace chino 18 19 inline void setting() 20 #if FILETEST 21 freopen("test.in", "r", stdin); 22 freopen("test.me.out", "w", stdout); 23 #endif 24 return; 25 26 27 inline int read() 28 char c = getchar(), up = c; int num = 0; 29 for(; c < ‘0‘ || c > ‘9‘; up = c, c = getchar()); 30 for(; c >= ‘0‘ && c <= ‘9‘; num = (num << 3) + (num << 1) + (c ^ ‘0‘), c = getchar()); 31 return up == ‘-‘ ? -num : num; 32 33 34 int n, m; 35 int S, T; 36 int maxflow, anssum; 37 int cntE = -1; 38 int head[inf]; 39 int cur[inf]; 40 int dep[inf]; 41 struct Edge 42 int to; 43 int flow; 44 int next; 45 e[inf << 1]; 46 std::queue <int> Q; 47 48 inline void AddEdge(int from, int to, int flow) 49 ++cntE; 50 e[cntE].to = to; 51 e[cntE].flow = flow; 52 e[cntE].next = head[from]; 53 head[from] = cntE; 54 return; 55 56 57 inline bool BFS(int s, int t) 58 memset(dep, -1, sizeof dep); 59 memcpy(cur, head, sizeof cur); 60 while(!Q.empty()) 61 Q.pop(); 62 Q.push(s); 63 dep[s] = 0; 64 while(!Q.empty()) 65 int x = Q.front(); 66 Q.pop(); 67 for(int i = head[x]; i ^ -1; i = e[i].next) 68 int y = e[i].to; 69 if(dep[y] == -1 && e[i].flow) 70 dep[y] = dep[x] + 1; 71 Q.push(y); 72 73 74 75 return dep[t] ^ -1; 76 77 78 int DFS(int s, int limit) 79 if(limit == 0 || s == T) 80 return limit; 81 int flow = 0; 82 int f = 0; 83 for(int i = cur[s]; i ^ -1; i = e[i].next) 84 cur[s] = i; 85 int to = e[i].to; 86 int Min = std::min(limit, e[i].flow); 87 if(dep[to] == dep[s] + 1 && (f = DFS(to, Min))) 88 flow += f; 89 limit -= f; 90 e[i].flow -= f; 91 e[i ^ 1].flow += f; 92 if(limit == 0) 93 break; 94 95 96 return flow; 97 98 99 inline void dinic(int s, int t) 100 while(BFS(s, t)) 101 maxflow += DFS(s, INF); 102 return; 103 104 105 inline int main() 106 memset(head, -1, sizeof head); 107 n = read(); 108 m = read(); 109 S = n + m + 1; 110 T = n + m + 2; 111 for(int i = 1; i <= n; i++) 112 int tmp = read(); 113 AddEdge(i + m, T, tmp); 114 AddEdge(T, i + m, 0); 115 116 for(int i = 1; i <= m; i++) 117 int a = read(); 118 int b = read(); 119 int v = read(); 120 anssum += v; 121 AddEdge(i, a + m, INF >> 1); 122 AddEdge(a + m, i, 0); 123 124 AddEdge(i, b + m, INF >> 1); 125 AddEdge(b + m, i, 0); 126 127 AddEdge(S, i, v); 128 AddEdge(i, S, 0); 129 130 dinic(S, T); 131 printf("%d\\n", anssum - maxflow); 132 return 0; 133 134 135 //namespace chino 136 137 int main()return chino::main();
例题2:luogu太空飞行计划问题
题意重点:每个仪器在购买后可以用无限次
不难看出也是一道最大权闭合图题 , 所以建图就是如之前一样了
那么怎么样输出方案呐
因为最小鸽C[S,T]将图G分成没有交的两个点集S和T
而答案就是集合S里所有的点
并不是说一个实验收入是负数就不要做这个实验
如题目样例
有些实验可能是给后面的实验买仪器 , 可能这个实验不赚钱 , 但是后面的实验不需要买仪器了 , 那这个方案可能更优
以上是关于最大权闭合图的主要内容,如果未能解决你的问题,请参考以下文章