【bzoj2427】【软件安装】tarjan缩点+树形依赖背包
(上不了p站我要死了,侵权度娘背锅)
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
3 10
5 5 6
2 3 4
0 1 1
Sample Output
5
wa了好久啊。。。在一些很细节的地方犯了很多低级错误
逐字比对之后才终于调出来,这wa率蹭蹭蹭就上去了。。T_T
其实这道题还是比较基础的。就是tarjan缩点之后,将所有树连向一个“超级根”,跑树上dp。
这个dp呢,是一个树形依赖背包。虽说是依赖背包,处理过后其实可以看做是一个分组背包。即,假设我们已处理出子树v占用m内存的最大价值,我们便可将子树v的各个值看做一个组,只能选择其中一种内存大小。而这道题的分组背包已经算是泛化物品了,外层for当前节点u的内存(从大到小),内层for子树v的内存大小(随便顺序)。
时间复杂度是o(n*m*m),可过
然后要附上wa的地方
看来是算法模板没有熟练,才会导致粗心的低级错误
完整代码(附wa点)
#include<stack>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=205;
const int M=1005;
stack<int> s;
int n,m,ww[N],vv[N];
int/*adde1*/ head1[N],end1[N*2],nxt1[N*2],hh1=0;
int/*adde2*/ head2[N],end2[N*2],nxt2[N*2],hh2=0;
int/*tarjan*/ dfn[N],low[N],idc=0,id[N],cnt=0;bool exi[N];
int cos[N],val[N],in[N];
int/*dfs*/ dp[N][M];
void adde1(int a,int b){
hh1++;
end1[hh1]=b;
nxt1[hh1]=head1[a];
head1[a]=hh1;
}
void adde2(int a,int b){
hh2++;
end2[hh2]=b;
nxt2[hh2]=head2[a];
head2[a]=hh2;
}
void tarjan(int u){
dfn[u]=low[u]=++idc;
s.push(u);
exi[u]=1;
for(int i=head1[u];i;i=nxt1[i]){
int v=end1[i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(exi[v]) low[u]=min(low[u],low[v]);
}
if(low[u]==dfn[u]){
cnt++;
int tmp;
while(s.top()!=u&&(!s.empty())){
tmp=s.top();s.pop();
id[tmp]=cnt;
exi[tmp]=0;
}
if(s.top()==u){
s.pop();
id[u]=cnt;
exi[u]=0;//最后在处理u时忘了。。
}
}
}
void dfs(int u){//printf("%d ",u);
dp[u][0]=0;
for(int i=head2[u];i;i=nxt2[i]){
int v=end2[i];
dfs(v);
for(int k=m-cos[u];k>=0;k--){//用了两次i,就导致了混乱
for(int j=k;j>=0;j--){
dp[u][k]=max(dp[u][k],dp[u][k-j]+dp[v][j]);
}
}
}
for(int j=m;j>=0;j--){
if(j-cos[u]>=0) dp[u][j]=dp[u][j-cos[u]]+val[u];
else dp[u][j]=0;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&ww[i]);
for(int i=1;i<=n;i++) scanf("%d",&vv[i]);
int d;
for(int i=1;i<=n;i++){
scanf("%d",&d);
if(d) adde1(d,i);
}
while(!s.empty()) s.pop();
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int u=1;u<=n;u++){
cos[id[u]]+=ww[u],val[id[u]]+=vv[u];
for(int i=head1[u];i;i=nxt1[i]){
int v=end1[i];
if(id[u]!=id[v]) adde2(id[u],id[v]),in[id[v]]++;
}
}
for(int i=1;i<=cnt;i++) if(!in[i]) adde2(0,i);
memset(dp,-27,sizeof(dp));
dfs(0);
int ans=0;
for(int i=1;i<=m;i++) ans=max(ans,dp[0][i]);
printf("%d\n",ans);
return 0;
}
总结:
1、像tarjan这种模板类型的要烂熟于心
【bzoj2427】【软件安装】tarjan缩点+树形依赖背包的更多相关文章
- BZOJ 2427 /HAOI 2010 软件安装 tarjan缩点+树形DP
终于是道中文题了.... 当时考试的时候就考的这道题.... 果断GG. 思路: 因为有可能存在依赖环,所以呢 先要tarjan一遍 来缩点. 随后就进行一遍树形DP就好了.. x表示当前的节点.j表 ...
- bzoj 2427 [HAOI2010]软件安装 Tarjan缩点+树形dp
[HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2029 Solved: 811[Submit][Status][Dis ...
- Gym - 100502G Outing (强连通缩点+树形依赖背包)
题目链接 问题:有n个人,最多选k个,如果选了某个人就必须选他指定的另一个人,问最多能选多少个人. 将每个人所指定的人向他连一条单向边,则每一个点都有唯一的前驱,形成的图是个基环树森林,在同一个强连通 ...
- 【BZOJ2427】[HAOI2010] 软件安装(缩点+树形DP)
点此看题面 大致题意: 有\(N\)个软件,每个软件有至多一个依赖以及一个所占空间大小\(W_i\),只有当一个软件的直接依赖和所有的间接依赖都安装了,它才能正常工作并造成\(V_i\)的价值.求在容 ...
- 【洛谷 P2515】 [HAOI2010]软件安装 (缩点+树形背包)
题目链接 看到代价和价值这两个关键词,肯定是首先要想到背包的. 但是图中并没有说这是棵树,所以先要\(Tarjan\)缩点,然后就是选课了,跑一遍树形背包就好了. 注意:缩点后应该是一个森林,应该用一 ...
- [BZOJ2427][HAOI2010]软件安装-tarjan缩点-树上dp
<题面> 这个题真伤人 之前Tarjan和树规都没学好,吃了不少亏,仔仔细细的搞了一天,收获颇丰 先来一个Tarjan的链接:$\mathbb{O}$ 题目的数据比较友好: $dp$不对: ...
- BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)
BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...
- BZOJ.4910.[SDOI2017]苹果树(树形依赖背包 DP 单调队列)
BZOJ 洛谷 \(shadowice\)已经把他的思路说的很清楚了,可以先看一下会更好理解? 这篇主要是对\(Claris\)题解的简单说明.与\(shadowice\)的做法还是有差异的(比如并没 ...
- bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)
菜菜推荐的“水题”虐了我一天T T...(菜菜好强强qwq~ 显然是个分数规划题,二分答案算出p[i]-mid*s[i]之后在树上跑依赖背包,选k个最大值如果>0说明还有更优解. 第一次接触树形 ...
随机推荐
- Java多线程学习——死锁的一个容易理解的例子
发生死锁的情况:多个线程需要同时占用多个共享资源而发生需要互相死循环等待的情况 public class Mirror { //镜子 } public class Lipstick { //口红 } ...
- 链路聚合teaming(网卡绑定技术)2
一.sentos7网卡绑定技术之teaming 这里介绍两种最常见的双网卡绑定模式: (1) roundrobin - 轮询模式 所有链路处于负载均衡状态,这种模式的特点增加了带宽,同时支持容错能力. ...
- python+selenium下弹窗alter对象处理01
alt.accept() : 等同于单击“确认”或者“OK” alt.dismiss() : ...
- Docker 容器(container)及资源限制
Container: 既然container是由image运行起来的,那么是否可以理解为container和image有某种关系?先来看张图: 其实可以理解为container只是基于image之后的 ...
- MySQL-快速入门(11)用户管理
1.权限表 存储用户权限信息表主要有:user.db.host.tables_priv.columns_priv.procs_priv. 1>user表: 记录允许连接到服务器的账号信息,里面的 ...
- MySql-Mysql技术内幕~SQL编程学习笔记(1)
1.MySQL的历史,一些相关概念. 2.MySQL数据类型 *通常一个页内可以存放尽可能多的行,那么数据库的性能就越好,选择一个正确的数据类型至关重要. 1>UNSIGNED类型: 将数字类型 ...
- Hyper-V Centos7 虚拟机固定IP
在网上看到很多篇文章,自己也去试验过,结果实现的效果都不是很理想,并不是自己所需要的,下面是我自己研究,最后成功的经验,希望能够帮到大家.少走一些弯路. 需求 1.无论物理机的网络环境怎么变化,都需要 ...
- [LeetCode] 47. 全排列 II
题目链接 : https://leetcode-cn.com/problems/permutations-ii/ 题目描述: 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例: 输入: [ ...
- P4290 [HAOI2008]玩具取名
传送门 $dp$ 设 $f[i][j][k]$ 表示初始为 $k$ 时,能否得到 $[i,j]$ 这一段子串 设 $pd[i][j][k]$ 表示长度为二的字符串 $ij$ 能否由 $k$ 得到 然后 ...
- Window Operations详解
window(windowLength, slideInterval):返回窗口长度为windowLength,每隔slideInterval滑动一次的window DStream countByWi ...