tarjan+树上背包

题目描述

现在我们的手头有 \(N\) 个软件,对于一个软件 \(i\),它要占用 \(W_i\) 的磁盘空间,它的价值为 \(V_i\)。我们希望从中选择一些软件安装到一台磁盘容量为 \(M\) 计算机上,使得这些软件的价值尽可能大(即 \(V_i\) 的和最大)。

但是现在有个问题:软件之间存在依赖关系,即软件 \(i\)只有在安装了软件 \(j\)(包括软件 \(j\) 的直接或间接依赖)的情况下才能正确工作(软件 \(i\) 依赖软件 \(j\) )。

幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为 \(0\)。

我们现在知道了软件之间的依赖关系:软件 \(i\) 依赖软件 \(D_i\)。

现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则 \(D_i=0\),这时只要这个软件安装了,它就能正常工作。


把依赖关系想象成有向边,由被依赖的软件指向依赖它的软件

那么一个点能被选到的条件就是,它的祖先被选

然后每个点都只有一个入度,还是有向边,所以如果没有环的话,这就是一个树!直接树上背包就能行了

那么考虑用 tarjan 缩点,每个强连通分量中,每两个点都可以互相到达,而这个“互相到达”,放在这个题里就是互相直接或间接的依赖

所以强连通分量里的点,如果选就都选,不选就都不选,这点很好理解

那么缩点后的图就是树了吗?

是的,对于一个强连通分量来讲,很显然,想要满足每两个点互相到达的要求,每个点都必须有它所在的这个强连通分量中,其它的点连过来的边(废话),那么,此时它的入度已经为一了,就不会再有这个强连通分量以外的点向这个点连边了

所以,只有可能是这个强连通分量向外连边,而且是连到那种只有一个点的强连通分量中

此时要把图缩完点的情况,每个强连通分量作为节点,重新连边

那么同时构建一个虚拟节点,由它向没有入度的强联通分量连边,这个虚拟点的 \(v,w\) 均为 \(0\)

直接以这个虚拟节点为根做树上背包dp 就行了


简单说一下树上背包咋做

\(f_{u,i}\) 表示在 \(u\) 这个点,用 \(i\) 的硬盘限制,能获得的最大价值

初始是 \(f_{u,i}=v_u,i\in [w_u,m]\)

再分别枚举 \(j\in [0,m-w_u]\) 表示对 所有 子树的限制,\(k\in[0,j]\) 表示对 当前 子树的限制

\[f_{u,j+w_u}=\max(f_{u,j+w_u},f_{v,k}+f_{u,j+w_u-k})
\]

这个转移方程也就很好理解了

另外这个 \(0-w_u<0\) 是有可能的,然后我用 ~j 来判断它是不是等于 \(-1\) 来结束循环节爆炸了

我再也不用位运算了

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
#define N 106
#define M 506
int fir[N],nex[N],to[N],tot;
int fir_[N],nex_[N],to_[N],tot_;
int dfn[N],low[N],dfscnt;
int scc[N],scccnt,indeg[N],sum_w[N],sum_v[N];
int stack[N],top;
int val[N],w[N];
int n,m;
int f[N][M];
inline void add(int u,int v){
to[++tot]=v;
nex[tot]=fir[u];fir[u]=tot;
}
inline void add_(int u,int v){
to_[++tot_]=v;
nex_[tot_]=fir_[u];fir_[u]=tot_;
}
void tarjan(int u){
stack[top++]=u;low[u]=dfn[u]=++dfscnt;
for(reg int v,i=fir[u];i;i=nex[i]){
v=to[i];
if(!dfn[v]){
tarjan(v);
low[u]=std::min(low[u],low[v]);
}
else if(!scc[v]) low[u]=std::min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
scccnt++;
do{
scc[stack[--top]]=scccnt;
sum_w[scccnt]+=w[stack[top]];sum_v[scccnt]+=val[stack[top]];
}while(stack[top]!=u);
}
}
inline void rebuild(){
for(reg int i=1;i<=n;i++){
for(reg int j=fir[i];j;j=nex[j])if(scc[i]!=scc[to[j]])
add_(scc[i],scc[to[j]]),indeg[scc[to[j]]]=1;
}
for(reg int i=1;i<=scccnt;i++)if(!indeg[i]) add_(scccnt+1,i);
}
void dfs(int u){
for(reg int i=sum_w[u];i<=m;i++) f[u][i]=sum_v[u];
reg int v,mm;
for(reg int i=fir_[u];i;i=nex_[i]){
v=to_[i];mm=m-sum_w[u];
dfs(v);
for(reg int j=mm;j>=0;j--){//j对 所有 子树的限制
for(reg int k=0;k<=j;k++)//k是对 当前 子树的限制
f[u][j+sum_w[u]]=std::max(f[u][j+sum_w[u]],f[v][k]+f[u][j+sum_w[u]-k]);
}
}
}
int main(){
n=read();m=read();
for(reg int i=1;i<=n;i++) w[i]=read();
for(reg int i=1;i<=n;i++) val[i]=read();
for(reg int i=1,x;i<=n;i++){
x=read();
if(x) add(x,i);
}
for(reg int i=1;i<=n;i++)if(!dfn[i]) tarjan(i);
rebuild();
// EN;
// for(reg int i=1;i<=scccnt;i++) std::printf("%d : %d ",i,fir_[i]);EN;
// std::puts("new : ");
// for(reg int i=1;i<=scccnt;i++){
// std::printf("%d : ",i);
// for(reg int j=fir_[i];j;j=nex_[j]) std::printf("%d ",to_[j]);
// EN;
// }
// for(reg int i=1;i<=scccnt;i++) std::printf("%d %d\n",sum_v[i],sum_w[i]);
dfs(scccnt+1);
std::printf("%d",f[scccnt+1][m]);
return 0;
}

[bzoj2427]P2515 [HAOI2010]软件安装(树上背包)的更多相关文章

  1. 【BZOJ2427】[HAOI2010]软件安装 Tarjan+树形背包

    [BZOJ2427][HAOI2010]软件安装 Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为 ...

  2. 【BZOJ2427】[HAOI2010]软件安装(动态规划,Tarjan)

    [BZOJ2427][HAOI2010]软件安装(动态规划,Tarjan) 题面 BZOJ 洛谷 题解 看到这类题目就应该要意识到依赖关系显然是可以成环的. 注意到这样一个性质,依赖关系最多只有一个, ...

  3. 洛谷 P2515 [HAOI2010]软件安装 解题报告

    P2515 [HAOI2010]软件安装 题目描述 现在我们的手头有\(N\)个软件,对于一个软件\(i\),它要占用\(W_i\)的磁盘空间,它的价值为\(V_i\).我们希望从中选择一些软件安装到 ...

  4. luogu P2515 [HAOI2010]软件安装 |Tarjan+树上背包

    题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为MM计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但 ...

  5. 【bzoj2427】[HAOI2010]软件安装 Tarjan+树形背包dp

    题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大).但是现 ...

  6. BZOJ2427:[HAOI2010]软件安装——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=2427 https://www.luogu.org/problemnew/show/P2515 现在 ...

  7. 【BZOJ2427】[HAOI2010] 软件安装(缩点+树形DP)

    点此看题面 大致题意: 有\(N\)个软件,每个软件有至多一个依赖以及一个所占空间大小\(W_i\),只有当一个软件的直接依赖和所有的间接依赖都安装了,它才能正常工作并造成\(V_i\)的价值.求在容 ...

  8. 洛谷 P2515 [HAOI2010]软件安装

    题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...

  9. 洛谷—— P2515 [HAOI2010]软件安装

    题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...

随机推荐

  1. flask入门 之 Python Shell (三)

    1.代码: #encoding:utf-8 from flask_sqlalchemy import SQLAlchemy from flask_script import Manager,Shell ...

  2. Prometheus 监控MySQL

    目录 0.简介 1.mysql_exporter部署 2.mysql报警规则 0.简介 文中主要监控MySQL/MySQL主从信息 版本:mysql-5.7,mysql_exporter-0.12.1 ...

  3. [安卓] 21、android studio 疑难杂症

    目录 1 gradle问题 1.1 gradle版本不匹配导致的错误: . 1 gradle问题 1.1 gradle版本不匹配导致的错误: 背景:在导入telink ble ota安卓源码时遇到an ...

  4. CVE-2019-17671:wrodpress 未授权访问漏洞-复现

    0x00 WordPress简介 WordPress是一款个人博客系统,并逐步演化成一款内容管理系统软件,它是使用PHP语言和MySQL数据库开发的,用户可以在支持 PHP 和 MySQL数据库的服务 ...

  5. Python——flask漏洞探究

    python的用途是真的多,就连网站也能做,这个有点像Java的Servlet flask基础 hello world 我们先从基础的开始,在网页上打出hello world,python代码如下: ...

  6. 使用Docker快速搭建PHP开发环境

    最近有个同事找过来,希望我对在很早之前写的一个PHP网站上增加一些功能,当时开发使用xampp构建的本地开发环境,但是现在我的笔记本电脑已经更新,没有当时的开发环境.本着尽量不往电脑上装无用软件的原则 ...

  7. 搞懂 XML 解析,徒手造 WEB 框架

    恕我斗胆直言,对开源的 WEB 框架了解多少,有没有尝试写过框架呢?XML 的解析方式有哪些?能答出来吗?! 心中没有答案也没关系,因为通过今天的分享,能让你轻松 get 如下几点,绝对收获满满. a ...

  8. 上班无聊,自己用python做个小游戏来打发时间

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取t.cn ...

  9. 详解 List接口

    本篇博文所讲解的这两个类,都是泛型类(关于泛型,本人在之前的博文中提到过),我们在学习C语言时,对于数据的存储,用的差不多都是数组和链表. 但是,在Java中,链表就相对地失去了它的存在价值,因为Ja ...

  10. API联调神器PostMan使用详解

    简介 创建 + 测试:创建和发送任何的HTTP请求,请求可以保存到历史中再次执行 Organize:使用Postman Collections为更有效的测试及集成工作流管理和组织APIs docume ...