码迷,mamicode.com
首页 > 其他好文 > 详细

最大权闭合图

时间:2019-08-24 17:04:16      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:来源   style   ret   freopen   struct   重点   题意   stdout   href   

前置芝士:最大流最小割

一. 啥是闭合图

一件事件x发生需要一个条件:

1. y事件已经发生

2. z事件已经发生

对于这样的依赖关系 , 我们可以用闭合来来描述或者解决

有向图的闭合图(closure)(来源于 胡伯涛《最小割模型在信息学竞赛中的应用》 论文 )

技术图片

物理意义:事物间依赖关系:一个事件要发生 , 她需要的所有前提也都一定发生

最大权闭合图是点权最大的闭合图

例题:[NOI2006]最大获利

技术图片

 一道求最大权闭合图的题

构图:

建源点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里所有的点

 

并不是说一个实验收入是负数就不要做这个实验

如题目样例

有些实验可能是给后面的实验买仪器 , 可能这个实验不赚钱 , 但是后面的实验不需要买仪器了 , 那这个方案可能更优

最大权闭合图

标签:来源   style   ret   freopen   struct   重点   题意   stdout   href   

原文地址:https://www.cnblogs.com/chiarochinoful/p/algorithm-closure.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!