P2762 太空飞行计划问题 网络流
题目描述
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}。实验Ej需要用到的仪器是I的子集RjÍI。配置仪器Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
输入输出格式
输入格式:
第1行有2 个正整数m和n。m是实验数,n是仪器数。接下来的m 行,每行是一个实验的有关数据。第一个数赞助商同意支付该实验的费用;接着是该实验需要用到的若干仪器的编号。最后一行的n个数是配置每个仪器的费用。
输出格式:
第1 行是实验编号;第2行是仪器编号;最后一行是净收益。
输入输出样例
说明
感谢@FlierKing 提供spj
n,m<=50
这道题数据是在windows生成的,输入数据中所有的换行都是'\r\n'而不是'\n'
读入某实验需要用到的仪器编号的时候,可以这么读入。(感谢@zhouyonglong的提供)
char tools[];
memset(tools,,sizeof tools);
cin.getline(tools,);
int ulen=,tool;
while (sscanf(tools+ulen,"%d",&tool)==)//之前已经用scanf读完了赞助商同意支付该实验的费用
{//tool是该实验所需仪器的其中一个
//这一行,你可以将读进来的编号进行储存、处理,如连边。
if (tool==)
ulen++;
else {
while (tool) {
tool/=;
ulen++;
}
}
ulen++;
}
这个是一个网络流的最小割问题,对于最小割的学习,推荐一个博客:https://www.cnblogs.com/TreeDream/p/5942354.html
对于这个输出路径,可以看一下一段话,别人写的:
首先可以确定,最后一次分层之前,网络流里已经没有增广路径了,接着就退出while循环,这个很好理解。然后想想看为点分层的条件,一个是还没有分层,另一个就是边的容量大于0。再结合问题想想,如果我要做一个实验,那么我必须要盈利,如果我得不到利益,我肯定不会去做对吧。放到图里就是从源点流出一道流到对应的实验,然后这个流分别流向这个实验需要的仪器,在流到汇点时,仪器与汇点连接的边的容量之和,一定要小于源点到实验这条边的容量,也就是说我的花费要小于我的利益,才能有收益。那么对于容量大于0的边(从源点到实验对应的点),其实剩余的容量就是我做这个实验的收益了,这也可以解释总收益减去最大流(即总花费)是净收益。那些残量为0的边说明这个实验得不到收益,那就不选,在分层时就不会分配到值。好了,那么那些残量大于0的边所连的实验就是要做的实验了。至于仪器嘛,因为实验与仪器之间的边容量是inf,所以只要实验选了,分了层了,它需要的仪器自然也会分到层。
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + ;
struct node
{
int u, v, c, f;
node(int u=,int v=,int c=,int f=):u(u),v(v),c(c),f(f){}
};
vector<node>e;
vector<int>G[maxn];
int level[maxn], iter[maxn];
int m;
void init()
{
for (int i = ; i <= maxn; i++) G[i].clear();
e.clear();
}
void add(int u,int v,int c)
{
e.push_back(node(u, v, c, ));
e.push_back(node(v, u, , ));
m = e.size();
G[u].push_back(m - );
G[v].push_back(m - );
} void BFS(int s)
{
memset(level, -, sizeof(level));
queue<int>que;
que.push(s);
level[s] = ;
while(!que.empty())
{
int u = que.front(); que.pop();
for(int i=;i<G[u].size();i++)
{
node &now = e[G[u][i]];
if(level[now.v]<&&now.c>now.f)
{
level[now.v] = level[u] + ;
que.push(now.v);
}
}
}
} int dfs(int u,int v,int f)
{
if (u == v) return f;
for(int &i=iter[u];i<G[u].size();i++)
{
node &now = e[G[u][i]];
if(now.c>now.f&&level[now.v]==level[u]+)
{
int d = dfs(now.v, v, min(f, now.c - now.f));
if(d>)
{
now.f += d;
e[G[u][i] ^ ].f -= d;
return d;
}
}
}
return ;
} int dinic(int s,int t)
{
int flow = ;
while()
{
BFS(s);
if (level[t] < ) return flow;
memset(iter, , sizeof(iter));
int f = ;
while ((f = dfs(s, t, inf)) > ) flow += f;
}
return flow;
}
vector<int>vec[];
int a[];
int main()
{
int n, m, sum = ;
cin >> n >> m;
int s = , t = n + m + ;
for(int i=;i<=n;i++)
{
int x;
cin >> x;
add(s, i, x);
sum += x;
char tools[];
memset(tools, , sizeof tools);
cin.getline(tools, );
int ulen = , tool;
while (sscanf(tools + ulen, "%d", &tool) == )
{
add(i, tool+n, inf);
if (tool == ) ulen++;
else {
while (tool) {
tool /= ;
ulen++;
}
}
ulen++;
}
}
for (int i = ; i <= m; i++)
{
cin >> a[i];
add(i + n, t, a[i]);
}
int ans = dinic(s, t);
for (int i = ; i <= n; i++) if (level[i] >= ) printf("%d ", i);
printf("\n");
for (int i = ; i <= m; i++) if (level[i + n] >= ) printf("%d ",i);
printf("\n");
printf("%d\n", sum - ans);
return ;
} /*
首先可以确定,最后一次分层之前,网络流里已经没有增广路径了,接着就退出while循环,这个很好理解。
然后想想看为点分层的条件,一个是还没有分层,另一个就是边的容量大于0。再结合问题想想,如果我要做一个实验,
那么我必须要盈利,如果我得不到利益,我肯定不会去做对吧。放到图里就是从源点流出一道流到对应的实验,
然后这个流分别流向这个实验需要的仪器,在流到汇点时,仪器与汇点连接的边的容量之和,一定要小于源点到实验这条边的容量,
也就是说我的花费要小于我的利益,才能有收益。那么对于容量大于0的边(从源点到实验对应的点),
其实剩余的容量就是我做这个实验的收益了,这也可以解释总收益减去最大流(即总花费)是净收益。
那些残量为0的边说明这个实验得不到收益,那就不选,在分层时就不会分配到值。
好了,那么那些残量大于0的边所连的实验就是要做的实验了。至于仪器嘛,因为实验与仪器之间的边容量是inf,
所以只要实验选了,分了层了,它需要的仪器自然也会分到层。
*/
P2762 太空飞行计划问题 网络流的更多相关文章
- 网络流24题:P2762 太空飞行计划问题
P2762 太空飞行计划问题 题目背景 题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,…,E ...
- 洛谷 P2762 太空飞行计划问题 P3410 拍照【最大权闭合子图】题解+代码
洛谷 P2762 太空飞行计划问题 P3410 拍照[最大权闭合子图]题解+代码 最大权闭合子图 定义: 如果对于一个点集合,其中任何一个点都不能到达此集合以外的点,这就叫做闭合子图.每个点都有一个权 ...
- Luogu 2762 太空飞行计划 / Libre 6001 「网络流 24 题」太空飞行计划 (网络流,最大流)
Luogu 2762 太空飞行计划 / Libre 6001 「网络流 24 题」太空飞行计划 (网络流,最大流) Description W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行 ...
- P2762 太空飞行计划问题(网络流24题之一)
题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的 ...
- 【luogu P2762 太空飞行计划问题】 题解
题目链接:https://www.luogu.org/problemnew/show/P2762 算是拍照那个题的加强下. 输入真的很毒瘤.(都这么说但好像我的过了?) #include <qu ...
- 洛谷 P4174 [NOI2006]最大获利 && 洛谷 P2762 太空飞行计划问题 (最大权闭合子图 && 最小割输出任意一组方案)
https://www.luogu.org/problemnew/show/P4174 最大权闭合子图的模板 每个通讯站建一个点,点权为-Pi:每个用户建一个点,点权为Ci,分别向Ai和Bi对应的点连 ...
- 洛谷 - P2762 - 太空飞行计划问题 - 最小割
https://www.luogu.org/problemnew/solution/P2762 最小割对应的点,在最后一次更新中dinic的bfs会把他的dep重置掉.所以可以根据这个性质复原最小割. ...
- P2762 太空飞行计划问题 最大权闭合子图
link:https://www.luogu.org/problemnew/show/P2762 题意 承担实验赚钱,但是要花去对应仪器的费用,仪器可能共用.求最大的收益和对应的选择方案. 思路 这道 ...
- luogu P2762 太空飞行计划问题
好像是最大权闭合图,也就是最大流最小割啦,找出最大流的路径输出,这题如何建模呢,一样的先设源点和汇点,源点向每个计划连capacity为赞助数的边,每个计划连相应装置capacity为无穷的边,每个装 ...
随机推荐
- 数据结构和算法(Golang实现)(11)常见数据结构-前言
常见数据结构及算法 数据结构主要用来组织数据,也作为数据的容器,载体. 各种各样的算法,都需要使用一定的数据结构来组织数据. 常见的典型数据结构有: 链表 栈和队列 树 图 上述可以延伸出各种各样的术 ...
- Mybatis-项目结构
源文件:https://github.com/569844962/Mybatis-Learn/blob/master/doc/Mybatis%E6%95%B4%E4%BD%93%E6%9E%B6%E6 ...
- Three.js三维模型几何体旋转、缩放和平移
创建场景中的三维模型往往需要设置显示大小.位置.角度,three.js提供了一系列网格模型对象的几何变换方法,从WebGL的角度看,旋转.缩放.平移对应的都是模型变换矩阵,关于矩阵变换内容可以观看本人 ...
- Python - Python的基础知识结构,学习方法、难点和重点
[原创]转载请注明作者Johnthegreat和本文链接. 相信大家都知道,Python很容易学,有编程基础的人,最多两个星期就可以很愉快的撸Python的代码了,那么具体涉及的知识有哪些,下面为大家 ...
- WPF中在Gmap.net中将Marker动起来
前一段时间说过一篇绘制极坐标的,这段时间对它进行了改造已经今非昔比了,功能实现了很多,我目的是让Marker动起来,然后还会绘制Route,上篇也就是简单的绘制了Route,没有关于Marker的相关 ...
- Python(10)
如果 a+b+c=1000,且 a^2+b^2=c^2(a,b,c 为自然数),如何求出所有a.b.c可能的组合? # 注意是三重循环 for a in range(0, 1001): for b i ...
- java学习(第五篇)包装类
一.Integer package com.test01; public class IntegerTest01 { public static void main(String[] args) { ...
- 素数&欧拉函数
素数表 const int maxN找[1,maxN)内的素数 int prime[int I]第I个素数 const int maxN=1e5+5; int prime[maxN]; bool ma ...
- 【集群实战】共享存储实时备份(解决nfs共享存储的单点问题)
1. nfs存储的单点问题 如果nfs服务器宕机了,则所有的nfs客户机都会受到影响.一旦宕机,会丢失部分用户的数据.为了解决单点问题,需要实现共享存储的实时备份,即:将nfs服务端共享目录下的数据实 ...
- 【Linux常见命令】sort命令
sort - sort lines of text files sort命令用于将文本文件内容加以排序. sort可针对文本文件的内容,以行为单位来排序. 语法: sort [OPTION]... [ ...