bzoj 2427: [HAOI2010]软件安装
Description
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
Input
第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 )
Output
一个整数,代表最大价值。
Sample Input
5 5 6
2 3 4
0 1 1
Sample Output
HINT
Source
由于是n个点n条边,所以是基环树森林,我们通过tarjan缩环后(环是捆绑选择的),就是森林
建立一个虚拟父亲后,就是一棵树了,然后就是经典的树型01背包问题了,但是zz选手竟然忘记树型背包了...
大致dp是这样的:f[i][j]表示i的子树花费j的体积产生的最大收益(如果选了i点就有值,不然就是0);
转移,对于以i为根的子树:
首先先不选i,然后和儿子的子树的收益进行合并:f[x][j]=max(f[x][j],f[x][k]+f[y][j-k]);
然后跟所有儿子搞完后,就来考虑选自身:
如果选不了自己的话,dp值为0,否则就直接加上(因为如果选不了i,那么i的子树中所有贡献都失效)
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int N=100050;
int gi()
{
int x=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*flag;
}
int head[N],to[N],nxt[N],v[N],w[N],low[N],dfn[N],zhan[N],vis[N],cnt,tt,sum,tot,w2[N],v2[N],fr[N];
int n,m,f[1000][1000],ru[N];
vector<int>p[N];
void lnk(int x,int y){
to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
}
void tarjan(int x){
low[x]=dfn[x]=++tt;vis[x]=1;zhan[++sum]=x;int y;
for(int i=head[x];i;i=nxt[i]){
y=to[i];
if(!dfn[y]){
tarjan(y);
low[x]=min(low[y],low[x]);
}
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
tot++;
do{
y=zhan[sum--];vis[y]=0;
w2[tot]+=w[y];v2[tot]+=v[y];fr[y]=tot;
}while(y!=x);
}
}
void dfs(int x){
for(int i=0;i<p[x].size();i++){
int y=p[x][i];dfs(y);
for(int j=m-v2[x];j>=0;j--){
for(int k=0;k<=j;k++)
f[x][j]=max(f[x][j],f[x][k]+f[y][j-k]);
}
}
for(int i=m;i>=0;i--){
if(i>=v2[x]) f[x][i]=f[x][i-v2[x]]+w2[x];
else f[x][i]=0;
}
}
int main(){
n=gi();m=gi();int x;
for(int i=1;i<=n;i++) v[i]=gi();
for(int i=1;i<=n;i++) w[i]=gi();
for(int i=1;i<=n;i++){
x=gi();if(x!=0) lnk(i,x);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=nxt[j]){
if(fr[i]!=fr[to[j]]) p[fr[to[j]]].push_back(fr[i]),ru[fr[i]]++;
}
int bigfa=tot+1;
for(int i=1;i<=tot;i++) if(!ru[i]) p[bigfa].push_back(i);
dfs(bigfa);printf("%d\n",f[bigfa][m]);
}
bzoj 2427: [HAOI2010]软件安装的更多相关文章
- bzoj 2427 [HAOI2010]软件安装 Tarjan缩点+树形dp
[HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2029 Solved: 811[Submit][Status][Dis ...
- BZOJ 2427 [HAOI2010]软件安装 | 这道树形背包裸题严谨地证明了我的菜
传送门 BZOJ 2427 题解 Tarjan把环缩成点,然后跑树形背包即可. 我用的树形背包是DFS序上搞的那种. 要注意dp数组初始化成-INF! 要注意dp顺推的时候也不要忘记看数组是否越界! ...
- BZOJ 2427: [HAOI2010]软件安装 tarjan + 树形背包
Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...
- BZOJ 2427: [HAOI2010]软件安装( dp )
软件构成了一些树和一些环, 对于环我们要不不选, 要么选整个环. 跑tarjan缩点后, 新建个root, 往每个入度为0的点(强连通分量) 连边, 然后跑树dp( 01背包 ) ---------- ...
- bzoj 2427: [HAOI2010]软件安装【tarjan+树形dp】
一眼最大权闭合子图,然后开始构图,画了画之后发现我其实是个智障网络流满足不了m,于是发现正确的打开方式应该是一眼树上dp 然后仔细看了看性质,发现把依赖关系建成图之后是个奇环森林,这个显然不能直接dp ...
- [BZOJ2427][HAOI2010]软件安装(Tarjan+DP)
2427: [HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1987 Solved: 791[Submit][Statu ...
- bzoj2427:[HAOI2010]软件安装(Tarjan+tree_dp)
2427: [HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1053 Solved: 424[Submit][Statu ...
- 【BZOJ2427】[HAOI2010]软件安装(动态规划,Tarjan)
[BZOJ2427][HAOI2010]软件安装(动态规划,Tarjan) 题面 BZOJ 洛谷 题解 看到这类题目就应该要意识到依赖关系显然是可以成环的. 注意到这样一个性质,依赖关系最多只有一个, ...
- BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP
BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP 题意: 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁 ...
随机推荐
- thinkphp框架知识点
基本配置 define('APP_DEBUG',true);//开启debug模式 //记录日志 'LOG_RECORD' => true, //系统日志在记录的时候需要开启debug调试模式, ...
- HDU5410--01背包+完全背包
CRB and His Birthday Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Oth ...
- mysql 各数据类型的 大小及长度
数字型 类型 大小 范围(有符号) 范围(无符号) 用途 TINYINT 1 字节 (-128,127) (0,255) 小整数值 SMALLINT 2 字节 (-32 768,32 767) (0, ...
- MySQL 性能优化的最佳20多条经验分享(三)(转)
16. 垂直分割 "垂直分割"是一种把数据库中的表按列变成几张表的方法,这样可以降低表的复杂度和字段的数目,从而达到优化的目的.(以前,在银行做过项目,见过一张表有100多个字段, ...
- 数据结构与算法(C/C++版)【栈与队列】
第三章<栈与队列> (一)栈简介 栈(Stack):只允许在一端进行插入或删除操作的线性表.首先栈是一种线性表,但是限定这种线性表只能在某一端进行插入和删除操作栈顶(top):线性表允许 ...
- centos7 简单搭建lnmp环境
1:查看环境: 1 2 [root@10-4-14-168 html]# cat /etc/redhat-release CentOS release 6.5 (Final) 2:关掉防火墙 1 [r ...
- C#判断ListBox是否显示了水平滚动条/横向滚动条
参看: Windows消息定义网址:http://wenku.baidu.com/link?url=9fesYjbLSDx9_TsLgSZSVoR7ELal-60x2p-lua_iPR44Xfekz0 ...
- Java开发小技巧(三):Maven多工程依赖项目
前言 本篇文章基于Java开发小技巧(二):自定义Maven依赖中创建的父工程project-monitor实现,运用我们自定义的依赖包进行多工程依赖项目的开发. 下面以多可执行Jar包项目的开发为例 ...
- 不同ios系统下mainscreen的applicationFrame和bounds值測试
打印结果(横屏,3.5寸.若4寸则最后一项对应添加) ios6: 2014-04-26 10:57:12.300 testAccount[18525:907] applicationFrame: {{ ...
- LeetCode OJ 之 Ugly Number II (丑数-二)
题目: Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime fact ...