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. PHP 预定义变量

    1.$_SERVER <?php $a=$_SERVER; var_dump($a); ?> 2.$_FILES <?php if($_FILES){ echo "< ...

  2. Python3中的函数 大全

    Python 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.Python提供了许多内建函数,比如print().但也可以自己创建 ...

  3. Flask之笔记集合

    目录 一.简述 二.基本使用 三.配置文件 四.路由系统 2.自定义正则路由 五.模版语言 六.请求和响应 七.Session 2.自定义session 八.蓝图 九.message 十.中间件 十一 ...

  4. webpack入门指南-step04

    一.建立项目 建一个文件夹,然后新建一个package.json的文件在项目根目录下 如果你使用git管理你的这个项目的话,建议你新建一个.gitignore文件,不要让git提交一些node依赖的模 ...

  5. PHP中的文件包含

    在PHP中,包含文件有两种方式:include和require.这两种方式的功能一样,只有一个区别,就是使用require包含一个文件时,如果出现错误,脚本不会继续执行:而如果使用include包含, ...

  6. Alpha版会议总结

    目前的进度: 实现了文字备忘的录入: 实现了提醒功能: 实现了可视化界面: 语音录入功能还没有完成: 界面相当粗糙: 遇到的问题: 语音录入按钮按下后没有反应,目前没有解决思路和方法. 原本的解屏功能 ...

  7. 【Coursera】支持向量机

    一.最大间隔分类器 1. 函数间隔:\(γ^{i} = y^{i}(w^{T} x + b)\), 改变w和b的量级,对分类结果不会产生任何影响,但是会改变函数间隔的大小.因此,直接对函数间隔求最大值 ...

  8. <构建之法>前三章读后感—软件工程

    本教材不同于其他教材一贯的理知识直接灌溉,而是以对话形式向我们传授知识的,以使我们更好地理解知识点,更加清晰明确. 第一章 第一章的概述中,书本以多种方式,形象生动地向我们阐述了软件工程的内容,也让我 ...

  9. yaf windows安装

    1.需要先下载 php_yaf模块.地址(http://pecl.php.net/package/yaf/2.3.2/windows) 看清你的php版本,然后在phpinfo中看Achitectur ...

  10. SSH框架面试题集锦

    Hibernate工作原理及为什么要使用Hibernate? 工作原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3.打开Session 4.创建事务Tran ...