[luoguP2762] 太空飞行计划问题(最大权闭合图—最小割—最大流)

传送门

如果将每一个实验和其所对的仪器连一条有向边,那么原图就是一个dag图(有向无环)

每一个点都有一个点权,实验为收益(正数),仪器为花费(负数)。

那么接下来可以引出闭合图的概念了。

闭合图是原图的一个点集,其中这个点集中每个点的出边所指向的点依然在这个点集中,那么这个点集就是个闭合图。

比如论文中的这个图:

在图 3.1 中的网络有 9 个闭合图(含空集):∅,{3,4,5},{4,5},{5},{2,4,5},{2,5},{2,3,4,5},{1,2,4,5},{1,2,3,4,5}

其中有大权和的闭合图是{3,4,5} ,权和为 4。

显然,我们目的就是求原图中的最大权闭合图。

为了求解这个,需要先把该图转化成网络。

增加一个超级原点s,s与每个实验连一条权值为实验利益的边。

增加一个超级汇点t,每个仪器与t连一条权值为仪器花费(正数)的边。

每个实验与它所依靠的仪器连一条权值为INF的边。

那么所有实验的费用(不是利益)减去最大流(最小割)即为最大的利益。

为什么呢?

根据论文中的证明,可以把最大权闭合图的问题转化为最小割。(然而看不懂)

下面转载一段比较简单的证明(然而还是看不懂)

首先引入结论,最小割所产生的两个集合中,其源点S所在集合(除去S)为最大权闭合图,接下来我们来说明一些结论。

  • 证明:最小割为简单割。

引入一下简单割的概念:割集的每条边都与S或T关联。(请下面阅读时一定分清最小割与简单割,容易混淆)

那么为什么最小割是简单割呢?因为除S和T之外的点间的边的容量是正无穷,最小割的容量不可能为正无穷。所以,得证。

  • 证明网络中的简单割与原图中闭合图存在一一对应的关系。(即所有闭合图都是简单割,简单割也必定是一个闭合图)。

证明闭合图是简单割:如果闭合图不是简单割(反证法)。那么说明有一条边是容量为正无穷的边,则说明闭合图中有一条出边的终点不在闭合图中,矛盾。

证明简单割是闭合图:因为简单割不含正无穷的边,所以不含有连向另一个集合(除T)的点,所以其出边的终点都在简单割中,满足闭合图定义。得正。

  • 证明最小割所产生的两个集合中,其源点S所在集合(除去S)为最大权闭合图。

首先我们记一个简单割的容量为C,且S所在集合为N,T所在集合为M。

则C=M中所有权值为正的点的权值(即S与M中点相连的边的容量)+N中所有权值为负的点权值的绝对值(即N中点与T中点相连边的容量)。记(C=x1+y1);(很好理解,不理解画一个图或

想象一下就明白了)。

我们记N这个闭合图的权值和为W。

则W=N中权值为正的点的权值-N中权值为负的点的权值的绝对值。记(W=x2-y2);

则W+C=x1+y1+x2-y2。

因为明显y1=y2,所以W+C=x1+x2;

x1为M中所有权值为正的点的权值,x2为N中权值为正的点的权值。

所以x1+x2=所有权值为正的点的权值之和(记为TOT).

所以我们得到W+C=TOT.整理一下W=TOT-C.

到这里我们就得到了闭合图的权值与简单割的容量的关系。

  因为TOT为定值,所以我们欲使W最大,即C最小,即此时这个简单割为最小割,此时闭合图为其源点S所在集合(除去S)。得正。

至此,我们就将最大权闭合图问题转化为了求最小割的问题。求最小割用最小割容量=最大流,即可将问题转化为求最大流的问题。

转载结束。

当然也可以这样理解,任意(非无穷大)割的值的意义都表示 实验集合中所不选的实验的利益 + 仪器集合中所选仪器的花费

那么 所有实验的利益 - 割 = 所有实验的利益 - (实验集合中所不选的实验的利益 + 仪器集合中所选仪器的花费) = 实验集合中所选的实验的利益 - 仪器集合中所选仪器的花费 = 总利益

要使得总利益最大,即使割最小,那么就可以通过求最小割来解决。

至于所选的实验和仪器,只需要找最后一次增广时能够到达的点(即集合S)即可。

——代码

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #define N 3010
  6 #define min(x, y) ((x) < (y) ? (x) : (y))
  7
  8 int n, m, sum, cnt, s, t, ans;
  9 int len[N], num[N][N], dis[N], cur[N];
 10 int head[N], next[N << 1], to[N << 1], val[N << 1];
 11
 12 inline int read()
 13 {
 14     int x = 0, f = 1;
 15     char ch = getchar();
 16     for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1;
 17     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘;
 18     return x * f;
 19 }
 20
 21 inline void add(int x, int y, int z)
 22 {
 23     to[cnt] = y;
 24     val[cnt] = z;
 25     next[cnt] = head[x];
 26     head[x] = cnt++;
 27 }
 28
 29 inline bool bfs()
 30 {
 31     std::queue <int> q;
 32     memset(dis, -1, sizeof(dis));
 33     dis[s] = 0;
 34     q.push(s);
 35     int i, u, v;
 36     while(!q.empty())
 37     {
 38         u = q.front();
 39         q.pop();
 40         for(i = head[u]; i ^ -1; i = next[i])
 41         {
 42             v = to[i];
 43             if(val[i] && dis[v] == -1)
 44             {
 45                 dis[v] = dis[u] + 1;
 46                 if(v == t) return 1;
 47                 q.push(v);
 48             }
 49         }
 50     }
 51     return 0;
 52 }
 53
 54 inline int dfs(int u, int maxflow)
 55 {
 56     if(u == t) return maxflow;
 57     int i, v, d, ret = 0;
 58     for(i = cur[u]; i ^ -1; i = next[i])
 59     {
 60         v = to[i];
 61         if(val[i] && dis[v] == dis[u] + 1)
 62         {
 63             d = dfs(v, min(val[i], maxflow - ret));
 64             ret += d;
 65             val[i] -= d;
 66             val[i ^ 1] += d;
 67             cur[u] = i;
 68             if(ret == maxflow) return ret;
 69         }
 70     }
 71     return ret;
 72 }
 73
 74 int main()
 75 {
 76     int i, j, x, l;
 77     std::string S;
 78     m = read();
 79     n = read();
 80     s = 0, t = n + m + 1;
 81     memset(head, -1, sizeof(head));
 82     for(i = 1; i <= m; i++)
 83     {
 84         x = read();
 85         add(s, i, x);
 86         add(i, s, 0);
 87         sum += x;
 88         getline(std::cin, S);
 89         l = S.length();
 90         for(j = 0; j < l; j++)
 91         {
 92             x = 0;
 93             if(S[j] == ‘ ‘) continue;
 94             while(isdigit(S[j]))
 95             {
 96                 x = (x << 1) + (x << 3) + S[j] - ‘0‘;
 97                 j++;
 98             }
 99             num[i][++len[i]] = x;
100         }
101         for(j = 1; j <= len[i]; j++)
102             add(i, num[i][j] + m, 1e9), add(num[i][j] + m, i, 0);
103     }
104     for(i = 1; i <= n; i++)
105     {
106         x = read();
107         add(i + m, t, x);
108         add(t, i + m, 0);
109     }
110     while(bfs())
111     {
112         for(i = s; i <= t; i++) cur[i] = head[i];
113         ans += dfs(s, 1e9);
114     }
115     for(i = 1; i <= m; i++)
116         if(dis[i] ^ -1)
117             printf("%d ", i);
118     puts("");
119     for(i = 1; i <= n; i++)
120         if(dis[i + m] ^ -1)
121             printf("%d ", i);
122     puts("");
123     printf("%d\n", sum - ans);
124     return 0;
125 }

转载内容来自:http://www.cnblogs.com/wuyiqi/archive/2012/03/12/2391960.html

参考:胡伯涛 《最小割模型在信息学竞赛中的应用》

时间: 2024-10-03 02:35:31

[luoguP2762] 太空飞行计划问题(最大权闭合图—最小割—最大流)的相关文章

太空飞行计划问题-最大权闭合图

题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}.实验Ej需要用到的仪器是I的子集RjÍI.配置仪器Ik的费用为ck美元.实验Ej的赞助商已同意为该实验结果支付pj美元.W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大.这里净收益是指进行实验所获得的全部

LuoguP2762 太空飞行计划问题(最大权闭合子图,最小割)

题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}.实验Ej需要用到的仪器是I的子集RjÍI.配置仪器Ik的费用为ck美元.实验Ej的赞助商已同意为该实验结果支付pj美元.W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大.这里净收益是指进行实验所获得的全部

最大权闭合图 最小割

闭合图为原图的一个子图, 满足任意一个节点的后继仍在闭合图中. 给原图的每个点以一个点权, 权值总和最大的闭合图称为最大权闭合图. 我们考虑利用最小割求解最大权闭合图. 首先, 为了权值最大, 我们贪心地将所有点权为正的点给选上, 但是这样可能会矛盾, 因为一个点权为正的点的后继可能点权为负. 我们考虑利用最小割, 减去最小的使方案合法的花费. 建立源点 S , 与 S 相连的意义是这个点被选择, 则初始的时候, 对于点权为正的点 i , 连边 (S, i, a[i]) . 建立汇点 T , 与

刷题总结——太空飞行计划(最大权闭合子图用最大流解决)

题目: 题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合 E={E1,E2,-,Em},和进行这些实验需要使用的全部仪器的集合 I={I1, I2,-In}. 实验 Ej 需要用到的仪器是 I 的子集 Rj∈I.配置仪器 Ik 的费用为 Ck 美元.实验 Ej 的赞助商已同意为该实验结果支付 Pj 美元.W 教授的任务是找出一个有效算法, 确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的

1737: 太空飞行计划问题 最大权闭合子图

1.建立两个超级点S,T. 2.对每个实验跟S链接一条容量为收入的边. 3.对每个一起跟T链接一条容量为花费的边. 4.对每个实验要用到的一起链接一条容量为无穷大的边. 链表 #include <iostream> #include <queue> #include <vector> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 101,MAX

bzoj 1497 [NOI2006]最大获利【最大权闭合子图+最小割】

不要被5s时限和50000点数吓倒!大胆网络流!我一个5w级别的dinic只跑了1s+! 看起来没有最大权闭合子图的特征--限制,实际上还是有的. 我们需要把中转站看成负权点,把p看成点权,把客户看成正权点,把c看成点权,然后把中转站点a.b作为客户点的依赖点 s点向所有正权点连边,流量为点权:所有负权点向t连边,流量为负点权(即正数!) 对于所有有依赖关系的点,由客户点向中转站点连边,流量为inf,也就是最大权闭合子图中的向其依赖点连边 连边的意义详见:http://www.cnblogs.c

最大权闭合子图(最小割)

最大权闭合子图(最大流最小割) •参考资料 [1]最大权闭合子图 •权闭合子图 存在一个图的子图,使得子图中的所有点出度指向的点依旧在这个子图内,则此子图是闭合子图. 在这个图中有8个闭合子图:∅,{3},{4},{2,4},{3,4},{1,3,4},{2,3,4},{1,2,3,4} •最大权闭合子图 在一个图中每个点具有点权值,在他的所有闭合子途中点权之和最大的即是最大权闭合子图. •详解 最大权闭合子图 结论 最大权闭合子图权值  =  所有权值为正的权值之和  -  最大流 •步骤 建

【最大权闭合子图/最小割】BZOJ3438-小M的作物【待填】

[题目大意] 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号),现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植可以获得bi的收益,而且有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以获得c2i的额外收益,所以,小M很快地算出了种植的最大收益. [思路] 首先,如果没有组合方案应该怎么做呢?其实非常方便. 首先建立超级源点S和超级汇点T,S

LibreOJ #6001. 「网络流 24 题」太空飞行计划 最大权闭合图

#6001. 「网络流 24 题」太空飞行计划 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合 E={E1,E2,?,Em} E = \{ E_1, E_2, \cdots, E_m \}E={E?1??,E?2??,?,E?m??},和进行这些实验