【洛谷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.题目中的依赖关系不一定是树,可 ...
随机推荐
- 阿里云服务器内部dns可能出错
今天部署一个阿里云服务器,所有配置项都改好了,就是连接不上本机. 反复查找,防火墙端口和网卡接口都配置对了,selinux也关闭了,但就是连接不上阿里云内网的ip. 由于连接是本机,把ip填写为127 ...
- DNS测试工具的使用(了解)
dig命令, host命令, nslookup命令,rndc命令 dig命令(直接测试DNS性能,不会查询/etc/hosts文件) dig [-t RR_TYPE] name [@SERVER] [ ...
- 1st 结对编程:简易四则运算
结对编程:简易四则运算 功能:进行简易的四则运算,并根据给出的结果判断正误. 实现:使用java的图形化界面实现. 导入包库 package six; import javax.swing.*; im ...
- JarvisOJ平台Web题部分writeup
PORT51 题目链接:http://web.jarvisoj.com:32770/ 这道题本来以为是访问服务器的51号端口,但是想想又不太对,应该是本地的51号端口访问服务器 想着用linux下的c ...
- HTML5资源站
前端里:http://www.yyyweb.com/ http://www.cnblogs.com/html5tricks/p/3925844.html
- 秒杀多线程第十四篇 读者写者问题继 读写锁SRWLock (续)
java 包实现了读写锁的操作: package com.multithread.readwritelock; import java.util.concurrent.CountDownLatch; ...
- 题解 P1888 【三角函数】
堆排序万岁! 小金羊又来水题了 #include <iostream> #include <queue> using namespace std; priority_queue ...
- java学习2-webserver测试工具soapUI使用
file-->new soap project-->输入project Name(随便)输入 WSDL地址,其他默认,点ok展开左侧加载的项目下的方法名,双击Request ,右侧出现测试 ...
- Toast与Snackbar的那点事
背景 Toast是Android平台上的常用技术.从用户角度来看,Toast是用户与App交互最基本的提示控件:从开发者角度来看,Toast是开发过程中常用的调试手段之一.此外,Toast语法也非常简 ...
- JDBC连接Oracle
数据库的操作是当前系统开发必不可少的开发部分之一,尤其是在现在的大数据时代,数据库尤为重要.但是你真的懂得Java与数据库是怎么连接的么? 先给大家一个数据库连接的简单实例: package com. ...