(上不了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缩点+树形依赖背包的更多相关文章

  1. BZOJ 2427 /HAOI 2010 软件安装 tarjan缩点+树形DP

    终于是道中文题了.... 当时考试的时候就考的这道题.... 果断GG. 思路: 因为有可能存在依赖环,所以呢 先要tarjan一遍 来缩点. 随后就进行一遍树形DP就好了.. x表示当前的节点.j表 ...

  2. bzoj 2427 [HAOI2010]软件安装 Tarjan缩点+树形dp

    [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2029  Solved: 811[Submit][Status][Dis ...

  3. Gym - 100502G Outing (强连通缩点+树形依赖背包)

    题目链接 问题:有n个人,最多选k个,如果选了某个人就必须选他指定的另一个人,问最多能选多少个人. 将每个人所指定的人向他连一条单向边,则每一个点都有唯一的前驱,形成的图是个基环树森林,在同一个强连通 ...

  4. 【BZOJ2427】[HAOI2010] 软件安装(缩点+树形DP)

    点此看题面 大致题意: 有\(N\)个软件,每个软件有至多一个依赖以及一个所占空间大小\(W_i\),只有当一个软件的直接依赖和所有的间接依赖都安装了,它才能正常工作并造成\(V_i\)的价值.求在容 ...

  5. 【洛谷 P2515】 [HAOI2010]软件安装 (缩点+树形背包)

    题目链接 看到代价和价值这两个关键词,肯定是首先要想到背包的. 但是图中并没有说这是棵树,所以先要\(Tarjan\)缩点,然后就是选课了,跑一遍树形背包就好了. 注意:缩点后应该是一个森林,应该用一 ...

  6. [BZOJ2427][HAOI2010]软件安装-tarjan缩点-树上dp

    <题面> 这个题真伤人 之前Tarjan和树规都没学好,吃了不少亏,仔仔细细的搞了一天,收获颇丰 先来一个Tarjan的链接:$\mathbb{O}$ 题目的数据比较友好: $dp$不对: ...

  7. BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)

    BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...

  8. BZOJ.4910.[SDOI2017]苹果树(树形依赖背包 DP 单调队列)

    BZOJ 洛谷 \(shadowice\)已经把他的思路说的很清楚了,可以先看一下会更好理解? 这篇主要是对\(Claris\)题解的简单说明.与\(shadowice\)的做法还是有差异的(比如并没 ...

  9. bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)

    菜菜推荐的“水题”虐了我一天T T...(菜菜好强强qwq~ 显然是个分数规划题,二分答案算出p[i]-mid*s[i]之后在树上跑依赖背包,选k个最大值如果>0说明还有更优解. 第一次接触树形 ...

随机推荐

  1. Java ——重写、多态、抽象类

    本节重点思维导图 重写 子类覆盖父类同名的方法 final关键字:不可变的 public static final PAGE_SIZE = 18; final修饰的类不能做为父类被子类继承. 多态 多 ...

  2. Discrete Mathematics and Its Applications | 1 CHAPTER The Foundations: Logic and Proofs | 1.1 Propositional Logic

    propositional variables (or statement variables), letters used for propositional variables are p, q, ...

  3. python 并发编程 多进程 互斥锁与join区别

    互斥锁与join 互斥锁和join都可以把并发变成串行 以下代码是用join实现串行 from multiprocessing import Process import time import js ...

  4. disabled_button 按钮按不下去

    X老师今天上课讲了前端知识,然后给了大家一个不能按的按钮,小宁惊奇地发现这个按钮按不下去,到底怎么才能按下去 检查元素 删除 按钮就可以摁了 出现答案

  5. python深度学习培训概念整理

    对于公司组织的人工智能学习,每周日一天课程共计五周,已经上了三次,一天课程下来讲了两本书的知识.发现老师讲的速度太快,深度不够,而且其他公司学员有的没有接触过python知识,所以有必要自己花时间多看 ...

  6. HTTP 常见相应状态码及含义

    1xx:信息 100 Continue 服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求. 101 Switching Protocols 服务器转换协议:服务器将 ...

  7. Kubernetes组件及网络基础

    在前面的部分了解了Pod的创建删除 ,查看信息等.那么我们怎么去管理Pod呢?我们可以通过 ReplicationController 去管理维护 Pod. Replication Controlle ...

  8. 【洛谷 P1879】【[USACO06NOV]玉米田Corn Fields】

    题目: 链接 思路: Q:如何想到是状压DP? A:那是因为(我看了标签)\(1 ≤ M ≤ 12; 1 ≤ N ≤ 12\),\(2 ^ {12}\) 不过才...(Win7计算器使用中)\(409 ...

  9. K8S工作原理

    kubernetes(k8s)是docker容器用来编排和管理的工具 我们通过kubectl向k8s Master发出指令.kubernetes Master主要是提供API Server.Sched ...

  10. django项目学习之异步框架celery

    最近用django一个网上商城项目的时候用两个扩展,感觉还不错,所以在此记录一下. 首先来说下celery,celery是一个处理异步任务的框架,需要下载celery包,一般在项目需要进行耗时操作的时 ...