bzoj2427:[HAOI2010]软件安装(Tarjan+tree_dp)
2427: [HAOI2010]软件安装
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1053 Solved: 424
[Submit][Status][Discuss]
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
2 3 4
0 1 1
Sample Output
HINT
Source
/*
开始一看这不是个基础的树型动规吗?(知道基础,但我不会啊),但是一看还有环嘞,苦逼了...
根据依赖关系可以画出来一张图,有三种可能的情况:
1.依赖关系构成一棵树。
2.依赖关系构成一个环。
3.依赖关系构成一个环下面吊着一棵树。
因为有2,3这些情况,所以要先有tarjan预处理一下,缩环为点,重新建图。
对于建好的图,跑一边树形背包即可,思想类似于01背包
f[x][tot]表示以x为根,容量为tot的最大收益。把x的各个子树看成物品
再枚举每个子树所分给的容量,tot从大到小转移。
*/
#include<iostream>
#include<cstdio>
#include<cstring> using namespace std;
int n,m,cnt,scc,ind,top,num;
int v[],w[];
int sv[],sw[];bool in_stack[];
int dfn[],low[],belong[];
int stack[],f[][],in[],head[],head2[];
struct node
{
int from;
int to;
int next;
}e[],e2[]; inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
} inline void insert(int from,int to)
{
e[++num].from=from;
e[num].to=to;
e[num].next=head[from];
head[from]=num;
} inline void insert2(int from,int to)
{
in[to]=;
e2[++num].from=from;
e2[num].to=to;
e2[num].next=head2[from];
head2[from]=num;
} void Tarjan(int u)
{
int now=;
dfn[u]=low[u]=++ind;
stack[++top]=u;
in_stack[u]=;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(in_stack[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
scc++;
while(now!=u)//统计环
{
now=stack[top--];in_stack[now]=;
belong[now]=scc;
sw[scc]+=w[now];
sv[scc]+=v[now];
}
}
}
void rebuild()//重建图
{
num=;
for(int x=;x<=n;x++)
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(belong[v]!=belong[x])
insert2(belong[x],belong[v]);
}
}
void dp(int x)
{
for(int i=head2[x];i;i=e2[i].next)
{
dp(e2[i].to);
for(int j=m-sw[x];j>=;j--)
{
for(int k=;k<=j;k++)//枚举子树的的限制。
f[x][j]=max(f[x][j],f[x][k]+f[e2[i].to][j-k]);
}
}
for(int j=m;j>=;j--)//完全背包
{
if(j>=sw[x])f[x][j]=f[x][j-sw[x]]+sv[x];
else f[x][j]=;
}
} int main()
{
n=read();m=read();
for(int i=;i<=n;i++)w[i]=read();
for(int i=;i<=n;i++)v[i]=read();
for(int i=;i<=n;i++)
{
int x=read();
if(x)insert(x,i);
}
for(int i=;i<=n;i++)
if(!dfn[i])Tarjan(i);
rebuild();
for(int i=;i<=scc;i++)
if(!in[i])
insert2(scc+,i);//这个地方要加1,因为根节点属于新的环。(不确定)
dp(scc+);
printf("%d\n",f[scc+][m]);
return ;
}
bzoj2427:[HAOI2010]软件安装(Tarjan+tree_dp)的更多相关文章
- [BZOJ2427][HAOI2010]软件安装(Tarjan+DP)
2427: [HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1987 Solved: 791[Submit][Statu ...
- [BZOJ2427][HAOI2010]软件安装-tarjan缩点-树上dp
<题面> 这个题真伤人 之前Tarjan和树规都没学好,吃了不少亏,仔仔细细的搞了一天,收获颇丰 先来一个Tarjan的链接:$\mathbb{O}$ 题目的数据比较友好: $dp$不对: ...
- BZOJ2427: [HAOI2010]软件安装 tarjan+树形背包
分析: 一开始我以为是裸的树形背包...之后被告知这东西...可能有环...什么!有环! 有环就搞掉就就可以了...tarjan缩点...建图记得建立从i到d[i]之后跑tarjan,因为这样才能判断 ...
- [BZOJ2427][HAOI2010]软件安装(tarjan+树形DP)
如果依赖关系出现环,那么对于一个环里的点,要么都选要么都不选, 所以每个环可以当成一个点,也就是强连通分量 然后就可以构造出一颗树,然后树形背包瞎搞一下就行了 注意要搞一个虚拟节点当根节点 Code ...
- 【BZOJ2427】[HAOI2010]软件安装 Tarjan+树形背包
[BZOJ2427][HAOI2010]软件安装 Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为 ...
- 【BZOJ-2427】软件安装 Tarjan + 树形01背包
2427: [HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 960 Solved: 380[Submit][Status ...
- bzoj 2427 [HAOI2010]软件安装 Tarjan缩点+树形dp
[HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2029 Solved: 811[Submit][Status][Dis ...
- 【bzoj2427】[HAOI2010]软件安装 Tarjan+树形背包dp
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大).但是现 ...
- bzoj2427: [HAOI2010]软件安装
Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...
随机推荐
- Vijos P1334 NASA的食物计划
解法 二维费用01背包问题 解法就是先枚举物品再枚举条件这里两个条件所以要枚举两个for 代码 #include <bits/stdc++.h> using namespace std; ...
- Ubuntu下安装oh-my-zsh
本文参考 https://www.jianshu.com/p/9a5c4cb0452d 此文已在ubuntu下确实安装成功,只不过懒得截图了,可以参照上述地址,我在他原基础上进行了一些更改. 安装Oh ...
- linux whereis-查找二进制程序、代码等相关文件路径
推荐:更多Linux 文件查找和比较 命令关注:linux命令大全 whereis命令用来定位指令的二进制程序.源代码文件和man手册页等相关文件的路径. whereis命令只能用于程序名的搜索,而且 ...
- 55.fielddata内存控制以及circuit breaker断路器
课程大纲 fielddata加载 fielddata内存限制 监控fielddata内存使用 circuit breaker 一.fielddata加载 fielddata加载到内存的过程是lazy加 ...
- Python初学者容易忽略的一些细节
1.Python中当让给变量1赋值上变量2的值时,变量1直接指向值在内存中存储的地址,即变量1存储的是变量2的值而不是指向变量 2."""的用法 1.多行注释 2.多行输 ...
- hihocoder 1032 最长回文子串(Manacher)
传送门 #include<queue> #include<cmath> #include<cstdio> #include<cstring> #incl ...
- Leetcode 86.分隔链表
分隔链表 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前. 你应当保留两个分区中每个节点的初始相对位置. 示例: 输入: head = 1-> ...
- poj 1379 模拟退火法
/* 模拟退火法: 找到一些随机点,从这些点出发,随机的方向坐标向外搜索: 最后找到这些随机点的最大值: 坑://if(xx>-eps&&xx<x+eps&& ...
- 转载 - Struts2基于XML配置方式实现对action的所有方法进行输入校验
出处:http://www.cnblogs.com/Laupaul/archive/2012/03/15/2398360.html http://www.blogjava.net/focusJ/arc ...
- vim下多行注释与解注释
1.多行注释 (1)按esc进入命令行模式 (2)按下Ctrl+v,进入区块模式,并使用上下键选择需要注释的多行 (3)按下“I”(大写)键,进入插入模式 (4)输入注释符(“//”或“#”等) (5 ...