【洛谷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.题目中的依赖关系不一定是树,可 ...
随机推荐
- 将java开发的wordcount程序提交到spark集群上运行
今天来分享下将java开发的wordcount程序提交到spark集群上运行的步骤. 第一个步骤之前,先上传文本文件,spark.txt,然用命令hadoop fs -put spark.txt /s ...
- HUST1017-Exact Cover
给出一个\(n\times m\)的01矩阵,每行最多有\(c\)个1,求一个精确覆盖,即选出一些行使得每列有有且仅有一个1.输出方案. 分析 被这个题坑到了啊!!第一次上HUSTOJ做题,不知道没有 ...
- 【bzoj4487】[Jsoi2015]染色问题 容斥原理
题目描述 棋盘是一个n×m的矩形,分成n行m列共n*m个小方格.现在萌萌和南南有C种不同颜色的颜料,他们希望把棋盘用这些颜料染色,并满足以下规定: 1. 棋盘的每一个小方格既可以染色(染成C种颜色中 ...
- C++解析(30):关于指针判别、构造异常和模板二义性的疑问
0.目录 1.指针的判别 2.构造中的异常 2.1 如果构造函数中抛出异常会发生什么? 2.2 如果析构函数中抛出异常会发生什么? 3.令人迷惑的写法 3.1 模板中的二义性 3.2 函数异常声明 4 ...
- OSPF虚连接简单配置
实验实例:<华为路由器学习指南>P715 本实例的拓扑结构如图:Area 2没有直接与骨干区域直接相连,Area 1被用作传输区域来连接Area 0与Area2.为了使Area2与骨干区域 ...
- Django之form表单提交并验证
1.提交的时候会报错 2. 需要在setting里面注释掉一句话,关闭跨站请求检查. 3. 注释掉以后,理论上就不报错了.可我还是卡壳了. 4. 通过在网上找方法,修复错误. 原因:表单action字 ...
- Cycle Sort (交换次数最少的排序)
该算法的效率并不高.但是却提供了一个很好的思路.如何让一个序列在最小交换次数下实现有序. Cycle Sort 翻译成中文是 圈排序. 这个圈在于需要交换的数据形成圈. 具体一点: 如: Array ...
- oracle中的substr()函数
SUBSTR(cExpression,nStartPosition [,nCharactersReturned])其中,cExpression指定要从其中返回字符串的字符表达式或备注字段:nStart ...
- 最近遇到的DISCUZ一些问题解决方法
“抱歉,您的请求来路不正确或表单验证串不符,无法提交” 打开“source\class\helper\helper_form.php”, 然后把“$_GET[‘formhash’] == formha ...
- UESTC--1300
原题链接:http://acm.uestc.edu.cn/problem.php?pid=1300 分析:dp,最长公共上升子列.对于两个序列num1[maxn],num2[maxn]: 如果num1 ...