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. 对PBFT算法的理解

    PBFT论文断断续续读了几遍,每次读或多或少都会有新的理解,结合最近的项目代码,对于共识的原理有了更清晰的认识.虽然之前写过一篇整理PBFT论文的博客,但是当时只是知道了怎么做,却不理解为什么.现在整 ...

  2. Paxos共识算法

    Paxos共识算法 paxos是一族用来解决分布式系统共识的基础算法,共识过程就是在一组节点上达成一个一致的结果.由于节点可能会错误,通讯消息也可能会丢失,所以建立共识是一个比较复杂的过程. paxo ...

  3. jdk8 Optional使用详解

    思考: 调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法. 原来解决方案: 我们首先要判断这个返回值是否为null,只有在非空的前提下才能将其作为其他方法的参数.这正是一些类似Guav ...

  4. linux命令系列 stat & touch

    1. stat - display file or file system status stat命令主要用于显示文件或文件系统的状态,详细信息 事实上,stat命令显示的是文件的I节点信息.Linu ...

  5. scrapy有用的(代理,user-agent,随机延迟等)

    代理 方法一(待测试) 见scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware import os # 设置相应的代理用户名密码,主机和 ...

  6. 第14讲:嵌入式SQL语言(基本技巧)

    一.交互式SQL的局限 & 嵌入式SQL的必要性 专业人员(如DBA)可以熟练地运用交互式SQL语言,但普通用户却不是那么容易上手,所以需要通过数据库应用程序来使用数据库.编写一个可以与数据库 ...

  7. teamwork 2

    1.访问上学期项目团队,学习他们的得失. 上学期学长们有一个项目是学霸系统,在看过了学长们的相关博客后,我们可以感受到学长们确实花费了不少心思,也看到了许多值得我们学习的地方. 首先,学长们在项目开始 ...

  8. web 08 struts2入门 struts2配置 struts包

    电影网站:www.aikan66.com 项目网站:www.aikan66.com游戏网站:www.aikan66.com图片网站:www.aikan66.com书籍网站:www.aikan66.co ...

  9. JavaBean 与 EJB 的区别

    JavaBean在一般情况下指的是实体类,在大部分情况下和POJO是同义词,基本构成就是一些字段和与之对应的 setter.getter方法,如果一个JavaBean需要在不同的JVM的进程中进行传递 ...

  10. jquery easyui datagrid getSelected getChecked获取选择行数据(勾选)数据

    要想获得上图所选取的元素只能用getChecked getSelected不能进行多个选择,只能单选 /* getSelected取得选中的数据,否则为null */ var user=$(" ...