Description

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

对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。

Limitation

\(1~\leq~n,~m~\leq~50\)

Solution

为啥题解里没人讲证明啊QAQ

简化一下题意以后,发现题意是这样的:

给定一张图,有左侧的点和右侧的点,左侧的点点权为正(对应试验),右侧的点点权为负(对应器材),如果选择了左侧的某个点就必须要选右边的一部分点。要求最大化点权和。

如果将左侧的点和右侧的点之间对应连边,如果该实验要求该器材就连一条边,那么问题就被转化为了这样一个问题:

给定一个有向图,点有点权,选择一个子图,满足子图上如果选择了一个点就必须选择它后继的所有点。最大化点权和。

这是一个经典的网络流问题,如果一个点被选择了则后继必须被选择,那么称该图是 闭合的,因此该问题叫做最大权闭合子图问题。可以使用最小割解决。

具体的建图方法为:

源点向所有正权点连结一条容量为权值的边

保留原图中所有的边,容量为正无穷

所有负权点向汇点连结一条容量为权值绝对值的边

则原图的最大权闭合子图的点权和即为所有正权点权值之和减去建出的网络流图的最小割。

以下约定源点为 \(s\),汇点为 \(t\)。

在最小割图上,如果割掉 \(s\) 和 \(u\) 之间的边,代表不选择 \(u\) 进入子图,如果割掉 \(v\) 和 \(t\) 之间的边,代表选择 \(v\) 进入子图。

求完最小割后,如果点 \(i\) 与 \(s\) 相连,那么子图上会选择点 \(i\),如果 \(i\) 与 \(t\) 相连,则不选择点 \(i\)。

考虑证明:

(部分证明内容参考CaptainChen的博客)

先证明得到的子图是闭合的:

首先考虑由于求得是最小割,一个点要么和 \(s\) 相连,要么和 \(t\) 相连,否则一定割掉它向 \(s\) 或 \(t\) 的一条边是没有意义的,因为割掉该边不会改变图的不连通性,最小割不会割掉它。

由于原图中的边全部是正无穷,最小割只会割掉源点和正权点之间或负权点和汇点之间的边。

考虑如果选择了正权点 \(u\),为了保证 \(s-t\) 不连通,必须割掉 \(u\) 所有后继中的负权点。这证明了如果选择了一个正权点那么所有的后继负权点都会被选择。

如果选择了正权点 \(u\),设 \(v\) 是 \(u\) 的后继且 \(v\) 的的权值为正,由于没有割掉 \(u\),通过 \(u-v\) 之间的正无穷边总能使得 \(s-v\) 联通,于是割掉 \(s-v\) 的边是没有意义的,最小割不会割掉这条边,这证明了如果选择了一个正权点那么该点的所有后继正权点都会被选择。

点权为 \(0\) 的情况同理。

考虑事实上选择的闭合子图的过程是不可能从一个负权点开始的,因为去掉这个负权点直接选择它的后继显然优于选择该点。于是只考虑选择正权点就可以包括所有的情况。证毕。

再证明得到的是最大权子图:

考虑如果 \(i\) 与 \(s\) 联通,那么选择 \(i\),否则不选择 \(i\)。所以最小割割掉的权值和是 不被选择的正权点权值和 + 被选择的负权点的权值的绝对值和 ,即 最小割 = \(\min\{\)没被选择的正权点权值和 + 被选择的负权点的权值的绝对值和\(\}\)

于是

\[\text{最大权闭合子图的权值和}~=~\max\{被选择的点权和\}~=~\text{正点权和} - \min\{\text{没被选择的正权点之和 + 被选择的负权点绝对值和}\}~=~\text{正点权和} - \text{最小割}
\]

证毕。

于是本题只需要按照上述方法建图即可。输出方案只需要输出与 \(s\) 联通的点。

Code

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif typedef long long int ll; namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
} template <typename T>
inline bool qr(T &x) {
char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
return (ch != '\r') && (ch != '\n');
} namespace OPT {
char buf[120];
} template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
int top=0;
do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
} const int maxn = 110;
const int INF = 10000000; struct Edge {
int u, v, flow;
Edge *nxt, *bk; Edge(const int _u, const int _v, const int _fl, Edge* &h) {
this->u = _u; this->v = _v; this->flow = _fl; this->nxt = h; h = this;
}
};
Edge *hd[maxn], *fir[maxn];
inline void cont(const int _u, const int _v, const int _flow) {
auto u = new Edge(_u, _v, _flow, hd[_u]), v = new Edge(_v, _u, 0, hd[_v]);
(u->bk = v)->bk = u;
} int n, m, s, t, ans;
int MU[maxn], val[maxn], trial[maxn], tol[maxn], dist[maxn];
std::vector<int>tool[maxn];
std::queue<int>Q; bool bfs();
int dfs(const int u, int canag); int main() {
freopen("1.in", "r", stdin);
qr(m); qr(n);
for (int i = 1, x = 0; i <= m; ++i) {
qr(MU[i]); ans += MU[i];
bool k;
do {
k = qr(x);
tool[i].push_back(x);
x = 0;
} while (k);
trial[i] = ++t;
}
for (int i = 1; i <= n; ++i) {qr(val[i]); tol[i] = ++t;}
s = ++t; ++t;
for (int i = 1; i <= m; ++i) {
cont(s, trial[i], MU[i]);
for (auto j : tool[i]) cont(trial[i], tol[j], INF);
}
for (int i = 1; i <= n; ++i) cont(tol[i], t, val[i]);
while (bfs()) {
for (int i = 1; i <= t; ++i) fir[i] = hd[i];
ans -= dfs(s, INF);
}
for (int i = 1; i <= m; ++i) if (dist[i]) qw(i, ' ', true);
putchar('\n');
for (int i = tol[1]; i <= tol[n]; ++i) if (dist[i]) qw(i - m, ' ', true);
putchar('\n');
qw(ans, '\n', true);
return 0;
} bool bfs() {
memset(dist, 0, sizeof dist);
Q.push(s); dist[s] = 1;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
for (auto e = hd[u]; e; e = e->nxt) if (e->flow > 0) {
if (dist[e->v]) continue;
dist[e->v] = dist[u] + 1;
Q.push(e->v);
}
}
return dist[t];
} int dfs(const int u, int canag) {
if ((u == t) || (!canag)) return canag;
int _flow = 0;
for (auto &e = fir[u]; e; e = e->nxt) if (e->flow > 0) {
int v = e->v;
if (dist[v] != (dist[u] + 1)) continue;
int f = dfs(v, std::min(canag, e->flow));
_flow += f; e->flow -= f; e->bk->flow += f;
if (!(canag -= f)) break;
}
return _flow;
}

【最小割】【网络流24题】【P2762】 太空飞行计划问题的更多相关文章

  1. LOJ6001 - 「网络流 24 题」太空飞行计划

    原题链接 Description 有个实验和个仪器,做实验有报酬买仪器有花费.每个实验都需要一些仪器,求最大净收益(实验报酬仪器花费),并输出一组方案. Solution 实验向所需仪器连边,实验的点 ...

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

    #6001. 「网络流 24 题」太空飞行计划 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测 ...

  3. Luogu 2762 太空飞行计划 / Libre 6001 「网络流 24 题」太空飞行计划 (网络流,最大流)

    Luogu 2762 太空飞行计划 / Libre 6001 「网络流 24 题」太空飞行计划 (网络流,最大流) Description W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行 ...

  4. 题解:线性规划与网络流24题 T2 太空飞行计划问题

    太空飞行计划问题 问题描述 W教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,-,Em},和进行这些实验需要 ...

  5. [Cogs727] [网络流24题#2] 太空飞行计划 [网络流,最小割]

    建图:源点—(w[i])—>实验—(∞)—>仪器—(cost[i])—>汇点, 如果该实验造成收益,则仪器到汇点的边在最小割中, 如果该实验造成损失,则源点到实验的边在最小割中, 故 ...

  6. 【刷题】LOJ 6001 「网络流 24 题」太空飞行计划

    题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合 \(E = \{ E_1, E_2, \cdots, E_m ...

  7. LibreOJ #6001. 「网络流 24 题」太空飞行计划

    \(\quad\) 与网络流有关的最值有三个:最大流,最小费用,最小割.这道题是最小割.想了好久,终于想明白最小割应该怎么用. \(\quad\) 先找出矛盾的事物.在这道题中,两件事是矛盾的:做实验 ...

  8. 【PowerOJ1737&网络流24题】太空飞行计划问题(最小割)

    题意: 思路: #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned in ...

  9. 网络流24题:P2762 太空飞行计划问题

    P2762 太空飞行计划问题 题目背景 题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,…,E ...

  10. 洛谷 P2762 太空飞行计划问题 P3410 拍照【最大权闭合子图】题解+代码

    洛谷 P2762 太空飞行计划问题 P3410 拍照[最大权闭合子图]题解+代码 最大权闭合子图 定义: 如果对于一个点集合,其中任何一个点都不能到达此集合以外的点,这就叫做闭合子图.每个点都有一个权 ...

随机推荐

  1. Linux常用软件安装与配置——目录

    http://blog.csdn.net/clevercode/article/details/45740431

  2. Spring笔记①--helloworld

    Spring Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架,它主要是为了解决企业应用开发的复杂性而诞生的: 目的:解决企业应用开发的复杂性 功能:使用基本的Javabean ...

  3. 手机连接wifi 访问本地服务器网站

    手机连本地wifi后访问 http://192.168.155.1:8001/loc 版权声明:本文为博主原创文章,未经博主允许不得转载.

  4. 运行时错误 429,ACTIVEX部件不能创建对象的解决方法小结

    错误描述: 发布在IIS上面的网站运行时出现如下错误: Microsoft VBscrīpt 运行时错误 错误 '800a01ad' ActiveX 部件不能创建对象 这个错误是asp组件未注册,而导 ...

  5. jquery获取父元素或父节点的方法

    jquery获取父元素方法比较多,比如parent(),parents(),closest()这些都能帮你实现查找父元素或节点,下面我们来一一讲解: 先举个例子: <ul class=" ...

  6. 使用Ubuntu编译Linux内核

    1.下载内核并解压到 /usr/src 目录下 在终端执行以下命令即可下载 4.16.14版本(目前最新的稳定版)的内核到当前shell打开的目录下 wget https://cdn.kernel.o ...

  7. 【win10】浏览器Chrome 和edge 体验对比与使用心得

    (1)Google和edge都内置了PDF阅读器,不用特意安装PDF软件了.桌面上的PDF文件可以直接用这两个浏览器打开. 然后对比来看,清晰度上美观度上,Chrome要比edge好一些.因为edge ...

  8. HttpURLConnection、HttpClient和Session

    原文地址:http://www.cnblogs.com/kross/p/3615695.html 一直没弄懂Session,cookies什么的登陆验证到底是怎么回事,昨天分别用HttpURLConn ...

  9. Python面向对象高级编程:__slot__(给实例添加方法、属性)

    纲要: 本章总的来说是给实例添加属性,给类添加方法两个主题,以及相应的作用范围.总结如下: 1.给实例添加属性(作用范围:当然是只对当前实例有效): 2.用__slots__限制可以给实例添加的属性( ...

  10. userData Behavior

    https://msdn.microsoft.com/zh-cn/vstudio/ms531424 userData Behavior This topic documents a feature o ...