[BZOJ2427]:[HAOI2010]软件安装(塔尖+DP)
题目传送门
题目描述
现在我们的手头有N个软件,对于一个软件i,它要占用${W}_{i}$的磁盘空间,它的价值为${V}_{i}$。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即${V}_{i}$的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件${D}_{i}$。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则${D}_{i}$=0,这时只要这个软件安装了,它就能正常工作。
输入格式
第1行:N, M
第2行:${W}_{1}$,${W}_{2}$,...,${W}_{i}$,...,${W}_{n}$
第3行:${V}_{1}$,${V}_{2}$,...,${V}_{i}$,...,${V}_{n}$
第4行:${D}_{1}$,${D}_{2}$,...,${D}_{i}$,...,${D}_{n}$
输出格式
一个整数,代表最大价值。
样例
样例输入:
3 10
5 5 6
2 3 4
0 1 1
样例输出:
5
数据范围与提示
0≤N≤100,0≤M≤500;0≤${W}_{i}$≤M;0≤${V}_{i}$≤1000;0≤${D}_{i}$≤N,${D}_{i}$≠i。
题解
看到这道题聪明的你应该会想到[NOIP2016]金明的预算方案。
可是这道题显然是那道题的升级版,一个软件在依赖别的软件的同时还有可能被另一个软件依赖,但是好消息是每一个软件只会依赖一个软件。
那么我们可以考虑树上DP。
首先,因为存在环,所以考虑塔尖的带权缩点,然后建立新图。
然后,将存好的这棵树进行先序遍历(DFS序),将遍历序存入队列que,并记录以i为跟节点的子树的大小coun。
所好了这些预处理之后,我们就可以愉快的进行DP啦~
先来定义DP,dp[i][j]表示从第i个软件到第n个软件,最多花费磁盘空间j所能获得的价值。
变成了01背包,对于每一个节点,会有两种情况:
1.安装它:占用磁盘空间,获得价值。
2.不安装:那么它的子树也不能安装。
那么写出状态转移方程:dp[i][j]=max(dp[i+1][j-w[que[i]]]+v[que[i]],dp[i+coun[que[i]]][j])。
时间复杂度:O(NM)。
模板题,一定要理解透彻!!!
代码时刻
#include<bits/stdc++.h>
using namespace std;
struct rec
{
int nxt;
int to;
}e[101],wzc[101];//e为旧图,wzc为新图
int head[101],cnt,headw[101],cntw;
int w[101],v[101],d[101],new_w[101],new_v[101];//注意此处d为新图中点的出度,后面两个数组也用在新图
int que[101],coun[101];//如题解
int dp[501][501];
int dfn[101],low[101],sta[101],ins[101],c[101],num,top,tot;//塔尖用
void add(int x,int y)//旧图建边
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void add_w(int x,int y)//新图建边
{
wzc[++cntw].nxt=headw[x];
wzc[cntw].to=y;
headw[x]=cntw;
}
void tarjan(int x)//塔尖带权缩点
{
dfn[x]=low[x]=++num;
sta[++top]=x;
ins[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
if(!dfn[e[i].to])
{
tarjan(e[i].to);
low[x]=min(low[x],low[e[i].to]);
}
else if(ins[e[i].to])
low[x]=min(low[x],dfn[e[i].to]);
}
if(dfn[x]==low[x])
{
tot++;
int y;
do
{
y=sta[top--];
ins[y]=0;
c[y]=tot;
new_w[tot]+=w[y];
new_v[tot]+=v[y];
}while(x!=y);
}
}
void dfs(int x)//dfs预处理
{
que[++que[0]]=x;
coun[x]=1;
for(int i=headw[x];i;i=wzc[i].nxt)
{
dfs(wzc[i].to);
coun[x]+=coun[wzc[i].to];
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
for(int i=1;i<=n;i++)
{
int y;
scanf("%d",&y);
if(y)add(y,i);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
for(int x=1;x<=n;x++)
for(int i=head[x];i;i=e[i].nxt)
if(c[x]!=c[e[i].to])
{
add_w(c[x],c[e[i].to]);
d[c[e[i].to]]++;
}
for(int i=1;i<=tot;i++)
if(!d[i])add_w(0,i);//将森林连成树
que[0]=-1;
dfs(0);
for(int i=tot;i;i--)
for(int j=0;j<=m;j++)
{
if(j>=new_w[que[i]])dp[i][j]=max(dp[i+1][j-new_w[que[i]]]+new_v[que[i]],dp[i+coun[que[i]]][j]);//dp
else dp[i][j]=dp[i+coun[que[i]]][j];
}
cout<<dp[1][m]<<endl;
return 0;
}
rp++
[BZOJ2427]:[HAOI2010]软件安装(塔尖+DP)的更多相关文章
- [BZOJ2427][HAOI2010]软件安装(Tarjan+DP)
2427: [HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1987 Solved: 791[Submit][Statu ...
- BZOJ2427:[HAOI2010]软件安装(树形DP,强连通分量)
Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...
- bzoj2427:[HAOI2010]软件安装(Tarjan+tree_dp)
2427: [HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1053 Solved: 424[Submit][Statu ...
- [bzoj2427][HAOI2010]软件安装——强连通分量+树形DP
题目大意 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
- bzoj2427: [HAOI2010]软件安装
Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...
- 题解【bzoj2427 [HAOI2010]软件安装】
Description 现在我们的手头有\(N\)个软件,对于一个软件\(i\),它要占用\(W_i\)的磁盘空间,它的价值为\(V_i\).我们希望从中选择一些软件安装到一台磁盘容量为\(M\)计算 ...
- [BZOJ2427][HAOI2010]软件安装-tarjan缩点-树上dp
<题面> 这个题真伤人 之前Tarjan和树规都没学好,吃了不少亏,仔仔细细的搞了一天,收获颇丰 先来一个Tarjan的链接:$\mathbb{O}$ 题目的数据比较友好: $dp$不对: ...
- [BZOJ2427][HAOI2010]软件安装(tarjan+树形DP)
如果依赖关系出现环,那么对于一个环里的点,要么都选要么都不选, 所以每个环可以当成一个点,也就是强连通分量 然后就可以构造出一颗树,然后树形背包瞎搞一下就行了 注意要搞一个虚拟节点当根节点 Code ...
- bzoj2427 [HAOI2010]软件安装——缩点+树形DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2427 今天的考试题...好不容易一次写对了树形DP,却没发现有环的情况... 发现自己 ta ...
随机推荐
- Ubuntu 19.04 下使用Remmina连接window服务器部署maven项目
先将打包好的war包上传到tomcat的webapps目录下 如果配置了tomcat的虚拟路径,那就放进虚拟路径的webapps文件李 修改tomcat安装目录下的conf/server.xml文件 ...
- Python自学笔记之计算机基础
osi七层协议应用层-表示层-会话层-传输层-网络层-数据链路层-物理层 无线网协议 ethernet 物理层:网线,光纤 数据链路层:arp协议 mac地址,广播 在广播域内传播 网络层:ip地址标 ...
- python中self与__init__怎么解释能让小白弄懂?
python中self与__init__怎么解释能让小白弄懂? 这个问题其实没那么简单. 只说一下自己的理解. python 里所有的 object 都有三个属性, 标识(identity), 类型( ...
- 续AspectJ篇
这篇将介绍AspectJ的第二种开发方法:基于注解的声明式-AspectJ. 与基于代理类的AOP实现相比,基于XML的声明式AspectJ要便捷的多,但是它也存在一些缺点,那就是在Spring文件中 ...
- SQL 基础语句整理
SQL教程 SELECT 语句 SELECT * FROM 表名称 DISTINCT 语句 SELECT DISTINCT 列名称 FROM 表名称 SELECT LastName,FirstName ...
- Linux下部署springboot项目的步骤及过程
最近在研究将springboot项目部署到Linux服务器上,由于springboot是内嵌了tomcat,所以可以直接将项目打包上传至服务器上.我是在idea上的项目,所以我就基于此说下过程. (一 ...
- C# wpf 使用资源文件 resx
随意新建一个wpf应用 在cs代码编辑,增加 using System.Resources; 放在最上 在方案新建文件夹 名 文件 在 文件 新建资源文件 资源.resx 资源.resx 添加字符串 ...
- 工具使用——使用XShell连接linux系统
1.首先到官网取下载一个XShell安装包,根据提示安装成功. 2.打开软件,点击新建连接 3.在新建连接页面输入,主机名称.主机地址.端口号,点击确定按钮. 4.在弹出的会话窗口中,选中我们刚刚创建 ...
- pycharm 激激活码
pycharm 激活码 [20191224亲测可用] http://lookdiv.com/neet/youd/codes.html
- super、this关键字
super调用(父类) 调用方法 语法: super.父类方法名(形参列表); 可以在子类方法和构造器中使用,调用父类被覆盖的方法. 实例变量 语法: super.父类实例变量名; ...