【洛谷P2515【HAOI2010】】软件安装
题目描述
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
输入输出格式
输入格式:
第1行:N, M (0<=N<=100, 0<=M<=500)
第2行:W1, W2, ... Wi, ..., Wn (0<=Wi<=M )
第3行:V1, V2, ..., Vi, ..., Vn (0<=Vi<=1000 )
第4行:D1, D2, ..., Di, ..., Dn (0<=Di<=N, Di≠i )
输出格式:
一个整数,代表最大价值
输入输出样例
输入样例#1:
3 10
5 5 6
2 3 4
0 1 1
输出样例#1:
5
算法:
树形DP
分析:
一看到这道题,就感觉和选课很相似,不过再仔细一看,就发现其实之间大有不同。
选课一题,是不可以成环的,因为先修课的先修课不可能成为后面的后修课,所以,判环是没必要的。
但是这道题,非常坑爹,它可以出现环。若出现a依赖b,b依赖c,c依赖a,那么我们究竟怎么搜索呢,而且转移方程也不好写。
我们通过观察发现,这种环状的问题,要是选了其中一个,那么就意味着要把整个环给选了,要么不选,就得整个都不选。
所以,我们就可以从这里入手,把一个个的环缩成一个个新的点,一个点代表了环的整体。
接下来就可以通过选课的后续思路,建造一棵左儿子右兄弟的二叉树,通过多叉树转二叉树进行记忆化搜索。
后面的就很简单了,状态转移方程就是要不要当前的兄弟,还是把机会分给兄弟和孩子。
不过中途有很多小点需要注意。
判环要用floyed的方法三重for来判断环,记得三个循环的变量顺序不能错,否则后果会判不到环。
其次,缩点建点的时候,主体分三个情况来判断:
1、这是新环,我需要建点来记录,他的价值和体积我都直接相加就好了。不过我们要记得把已经转移的新点的原来两个旧点序号变成负数,而新点的下标+旧点的内容恰好是等于n的,每一个环一一对应,不多也不会少,详情见代码操作。
2、这是旧环,我发现了新的点,这个点在环内。那么我就把这个点并到环中,把价值和体积也加到新点上,然后把原来这个旧环的密码推到这个新点上。
3、找到一个新点,他和一个旧环有联系,但不属于这个环的一部分,于是把它的从属关系推到新的点上。
步骤简化为:判环+缩点+多叉转二叉+记忆化搜索。
上代码:
#include<cstdio>
#include<iostream>
#include<cctype>
using namespace std; const int size=;
int n,m,ans,sum,d[size],v[size],w[size],f[size][*size],b[size],c[size];
bool a[size][size]; //是否连通 inline int read() //读入优化
{
int f=,x=;
char c=getchar();
while (!isdigit(c))
f=c=='-'?-:,c=getchar();
while (isdigit(c))
x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
} void floyed() //Floyd判环
{
int i,j,k;
for (k=;k<=n;k++)
for (i=;i<=n;i++)
for (j=;j<=n;j++)
if (a[j][k]&&a[k][i])
a[j][i]=;
} void connect() //缩点建点
{
ans=n; //ans表示新点的下标
int i,j;
for (i=;i<=ans;i++)
for (j=;j<=ans;j++)
{
if (a[i][j]&&a[j][i]&&i!=j&&w[i]>&&w[j]>) //发现新环
{
sum--; //sum是旧点的密码
ans++;
w[ans]=w[i]+w[j];
v[ans]=v[i]+v[j];
w[i]=w[j]=sum;
}
else
if (w[d[j]]<&&w[j]>) //发现旧环
{
if (a[d[j]][j]&&a[j][d[j]]) //属于环
{
w[n-w[d[j]]]+=w[j];
v[n-w[d[j]]]+=v[j];
w[j]=w[d[j]];
}
else //不属于环
if (a[d[j]][j]&&!a[j][d[j]]||!a[d[j]][j]&&a[j][d[j]])
d[j]=n-w[d[j]];
}
}
} int dfs(int root,int val) //记忆化搜索
{
if (f[root][val]>)
return f[root][val];
if (root==||val<=)
return ;
f[b[root]][val]=dfs(b[root],val);
f[root][val]=f[b[root]][val];
int i,k=val-w[root];
for (i=;i<=k;i++)
{
f[b[root]][k-i]=dfs(b[root],k-i);
f[c[root]][i]=dfs(c[root],i);
f[root][val]=max(f[root][val],v[root]+f[b[root]][k-i]+f[c[root]][i]);
}
return f[root][val];
} int main()
{
int i;
n=read();
m=read();
for (i=;i<=n;i++)
w[i]=read();
for (i=;i<=n;i++)
v[i]=read();
for (i=;i<=n;i++)
{
d[i]=read();
a[d[i]][i]=;
}
floyed();
connect();
for (i=;i<=ans;i++) //模拟链表
if (w[i]>)
{
b[i]=c[d[i]];
c[d[i]]=i;
}
printf("%d",dfs(c[],m));
return ;
}
这道题其实难度很大,不过只要把原理弄懂,代码还是很好打的,主要就是围绕着如何更加简便地进行记忆化搜索,然后一层层地进行优化,这道题用到的就是判环和缩点的知识。
嗯,就这样了。
【洛谷P2515【HAOI2010】】软件安装的更多相关文章
- 洛谷 P2515 [HAOI2010]软件安装 解题报告
P2515 [HAOI2010]软件安装 题目描述 现在我们的手头有\(N\)个软件,对于一个软件\(i\),它要占用\(W_i\)的磁盘空间,它的价值为\(V_i\).我们希望从中选择一些软件安装到 ...
- 洛谷—— P2515 [HAOI2010]软件安装
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
- 洛谷 P2515 [HAOI2010]软件安装
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
- 洛谷——P2515 [HAOI2010]软件安装
https://www.luogu.org/problem/show?pid=2515#sub 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中 ...
- 洛谷 P2515 [HAOI2010]软件安装(缩点+树形dp)
题面 luogu 题解 缩点+树形dp 依赖关系可以看作有向边 因为有环,先缩点 缩点后,有可能图不联通. 我们可以新建一个结点连接每个联通块. 然后就是树形dp了 Code #include< ...
- 洛谷P2515 [HAOI2010]软件安装(tarjan缩点+树形dp)
传送门 我们可以把每一个$d$看做它的父亲,这样这个东西就构成了一个树形结构 问题是他有可能形成环,所以我们还需要一遍tarjan缩点 缩完点后从0向所有入度为零的点连边 然后再跑一下树形dp就行了 ...
- luogu P2515 [HAOI2010]软件安装 |Tarjan+树上背包
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为MM计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但 ...
- [bzoj2427]P2515 [HAOI2010]软件安装(树上背包)
tarjan+树上背包 题目描述 现在我们的手头有 \(N\) 个软件,对于一个软件 \(i\),它要占用 \(W_i\) 的磁盘空间,它的价值为 \(V_i\).我们希望从中选择一些软件安装到一台磁 ...
- P2515 [HAOI2010]软件安装
树形背包 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> ...
- luogu P2515 [HAOI2010]软件安装
传送门 看到唯一的依赖关系,容易想到树型dp,即\(f_{i,j}\)表示选点\(i\)及子树内连通的点,代价为\(j\)的最大价值,然后就是选课那道题 但是要注意 1.题目中的依赖关系不一定是树,可 ...
随机推荐
- 3dContactPointAnnotationTool开发日志(三一)
在玩的时候遇到了一个python的问题: Traceback (most recent call last): File ".\convert.py", line 13, in ...
- Beta 阶段项目计划
Beta 阶段项目计划 NewTeam 目标 实现用户数量的目标. 在多个平台发布 完成稳定运行.界面优雅的客户端 充分测试,避免发布后出现bug影响用户使用 及时更新开发文档 合理安排时间,避免和其 ...
- 【leetcode】54.Spiral Matrix
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral or ...
- Java MD5加密类
/************************************************* md5 类实现了RSA Data Security, Inc.在提交给IETF 的RFC1321中 ...
- 【C++】深度探索C++对象模型读书笔记--构造函数语义学(The Semantics of constructors)(四)
成员们的初始化队伍(member Initia 有四种情况必须使用member initialization list: 1. 当初始化一个reference member时: 2. 当初始化一个co ...
- 第149天:javascript中this的指向详解
js中的this指向十分重要,了解js中this指向是每一个学习js的人必学的知识点,今天没事,正好总结了js中this的常见用法,喜欢的可以看看: 1.全局作用域或者普通函数中this指向全局对象w ...
- 第93天:CSS3 中边框详解
CSS3 边框详解 其中边框圆角.边框阴影属性,应用十分广泛,兼容性也相对较好,具有符合渐进增强原则的特征,我们需要重点掌握. 一.边框圆角 border-radius 每个角可以设置两个值 ...
- 学习websocket-SignalR,MVC中使用SignalR打造酷炫实用的即时通讯
http://www.cnblogs.com/Leo_wl/p/4793284.html http://www.fangsi.net/archives/1144.html
- 【bzoj1878】[SDOI2009]HH的项链
考虑非莫队的离线算法.. 若[l,r]中有重复数值很麻烦,考虑取一个数为代表(最左或最右) 1.最左:用BIT,先把所有第一个出现的数扔进去,将询问左端点升序,每次都可能产生历史的无用点,并出现新的“ ...
- DotNet,PHP,Java的数据库连接代码大全(带演示代码)
C#数据库连接字符串 Web.config文件 <connectionStrings> <!--SQLServer数据库连接--> <add name="con ...