好久没有搞过树形dp的题了,它对新人很不友好,我就来补一发超详细的题解吧。

一、题目

点此看题
题意
给定一棵树,其中每个号节点如果被点亮,就会对周围相连的节点发出ci格能量,点亮第i个节点需要的能量点数为di。问能点亮整棵树的最小能量花费。
数据范围
对于50%50\%50%的数据,max⁡ci<=1,n<=100000\max{ci}<=1,n<=100000maxci<=1,n<=100000
对于另外50%50\%50%的数据,max⁡ci<=5,n<=2000\max{ci}<=5,n<=2000maxci<=5,n<=2000

二、解法

第一眼看到这个数据范围,觉得特别神奇,我们考虑数据分治。
0x01 贪心
先来考虑第一个范围,因为此时的ccc只包含0或1,我们考虑c=1c=1c=1的点的点亮顺序。无论怎么点亮,减少的能量花费总量都是一定的(可以自举例子加深理解),所以最优解和顺序无关,我们只需优先点亮c=1c=1c=1的点即可。
0x02 树形dp
第二个范围就没有那么容易了,受贪心的启发,我们考虑点亮顺序。利用树形dp,我们对局部的点亮顺序进行考虑我们定义dp[i][0/1]dp[i][0/1]dp[i][0/1]为对于第iii个节点先染 它///它的父亲,并把iii及iii的子树染完的最小花费。
显然答案为dp[1][0]dp[1][0]dp[1][0](111的父亲不存在,用它统计最优答案)。
现在我们考虑对dpdpdp数组的转移。
由于ccc并不是很大,我们可以把它作为一个维度,为了辅助转移,我们再定义tmp[s]tmp[s]tmp[s]为染完uuu的子树,并且接受了儿子们值为sss的能量传递的最小花费(这里并不用去管uuu是否被染色),我们先遍历完子树,再用滚动数组的形式合并子树的信息,详细操作见下。

memset(tmp,0x3f,sizeof tmp);
tmp[0][0]=0;//初始化
for(int i=f[u];i;i=e[i].next)//枚举每个儿子
{   int v=e[i].v;if(v==fa) continue;cur^=1;//滚动数组,用tmp[cur^1]更新tmp[cur]memset(tmp[cur],0x3f,sizeof tmp[cur]);for(int j=0;j<=sum-c[v];j++)//此时我们可以使用dp[v]{tmp[cur][j+c[v]]=min(tmp[cur][j+c[v]],tmp[cur^1][j]+dp[v][0]);//先点亮vtmp[cur][j]=min(tmp[cur][j],tmp[cur^1][j]+dp[v][1]);//先点亮u}
}

拿到了tmptmptmp之后,更新就要简单一些了,我们可写出如下转移:
dp[u][0]=min(dp[u][0],max(tmp[i],tmp[i]−i+d[u]));dp[u][0]=min(dp[u][0],max(tmp[i],tmp[i]-i+d[u]));dp[u][0]=min(dp[u][0],max(tmp[i],tmp[i]−i+d[u]));
dp[u][1]=min(dp[u][1],max(tmp[i],tmp[i]−i+d[u]−c[fa]));dp[u][1]=min(dp[u][1],max(tmp[i],tmp[i]-i+d[u]-c[fa]));dp[u][1]=min(dp[u][1],max(tmp[i],tmp[i]−i+d[u]−c[fa]));
其中iii是从儿子得到的能量,我们防止能量溢出(即有多余的能量),故取max。

0x3f 代码
作者口胡可能难以理解,更多请看完整版代码,也可以单独向作者提问qwq。

#include <cstdio>
#include <cstring>
const int MAXN = 100005;
const int MAXM = 2005;
int read()
{int x=0,flag=1;char c;while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();return x*flag;
}
int n,tot,ans,mc,d[MAXN],c[MAXN],f[MAXN];
struct edge
{int v,next;
} e[MAXN*2];
int max(int x,int y)
{if(x<y) return y;return x;
}
int min(int x,int y)
{if(x<y) return x;return y;
}
int dp[MAXM][2],tmp[2][5*MAXM];
void dfs(int u,int fa)
{int sum=0,cur=0;for(int i=f[u]; i; i=e[i].next){int v=e[i].v;if(v==fa) continue;dfs(v,u);sum+=c[v];}memset(tmp,0x3f,sizeof tmp);tmp[0][0]=0;for(int i=f[u]; i; i=e[i].next){int v=e[i].v;if(v==fa) continue;cur^=1;memset(tmp[cur],0x3f,sizeof tmp[cur]);for(int j=0; j<=sum-c[v]; j++){tmp[cur][j+c[v]]=min(tmp[cur][j+c[v]],tmp[cur^1][j]+dp[v][0]);tmp[cur][j]=min(tmp[cur][j],tmp[cur^1][j]+dp[v][1]);}}dp[u][0]=dp[u][1]=0x3f3f3f3f;for(int i=0; i<=sum; i++){dp[u][0]=min(dp[u][0],max(tmp[cur][i],tmp[cur][i]-i+d[u]));dp[u][1]=min(dp[u][1],max(tmp[cur][i],tmp[cur][i]-i+d[u]-c[fa]));}return ;
}
int main()
{n=read();for(int i=1; i<=n; i++)d[i]=read();for(int i=1; i<=n; i++)c[i]=read(),mc=max(mc,c[i]);for(int i=1; i<n; i++){int u=read(),v=read();e[++tot]=edge{u,f[v]},f[v]=tot;e[++tot]=edge{v,f[u]},f[u]=tot;}if(mc<=1){for(int i=1; i<=n; i++)if(c[i]==1){ans+=d[i];d[i]=0;for(int j=f[i]; j; j=e[j].next)d[e[j].v]--;}for(int i=1; i<=n; i++)if(d[i]>0)ans+=d[i];printf("%d\n",ans);return 0;}dfs(1,0);printf("%d\n",dp[1][0]);return 0;
}

[SHOI2015]聚变反应炉相关推荐

  1. 4593: [Shoi2015]聚变反应炉

    4593: [Shoi2015]聚变反应炉 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 34  Solved: 19 [Submit][Statu ...

  2. 洛谷 P4269 [SHOI2015] 聚变反应炉 题解【贪心】【DP】

    树上游戏-二合一? 题目描述 曾经发明了零件组装机的发明家 SHTSC 又公开了他的新发明:聚变反应炉--一种可以产生大量清洁能量的神秘装置. 众所周知,利用核聚变产生的能量有两个难点:一是控制核聚变 ...

  3. 洛谷 P4269 / loj 2041 [SHOI2015] 聚变反应炉 题解【贪心】【DP】

    树上游戏..二合一? 题目描述 曾经发明了零件组装机的发明家 SHTSC 又公开了他的新发明:聚变反应炉--一种可以产生大量清洁能量的神秘装置. 众所周知,利用核聚变产生的能量有两个难点:一是控制核聚 ...

  4. bzoj4593: [Shoi2015]聚变反应炉

    这道题的难点其实是在设DP方程,见过就应该会了 令f0,i表示先激发i的父亲,再激发i,把i的整棵子树都激发的最小费用 f1,i表示先激发i,再激发i的父亲,把i的整棵子树都激发的最小费用 设x,y为 ...

  5. [SHOI2015]聚变反应炉[树dp、贪心]

    题意 给定一棵 \(n\) 个点的树,每个点有一个启动能量 \(d\) 和传递能量 \(c\) ,如果一个点被启动了,就会向和他直接相连的点发送 \(c\) 的能量,初始所有节点能量为0,问最少多少能 ...

  6. [SHOI 2015] 聚变反应炉(树形背包 + 树形 DP) | 错题本

    文章目录 题目 分析 代码 题目 [SHOI 2015] 聚变反应炉 分析 对于树上一个点操作后对相邻节点产生影响的题目,DP 状态的定义需要考虑父节点的影响. 定义 DP 状态 dp[u][0/1] ...

  7. 【LOJ】#2041. 「SHOI2015」聚变反应炉

    题解 这显然是一道题拆成两道 然后我胡乱分析了一波,决定第一题就用点度贪心(反正散播的能量肯定能被使用),然后过了 第二题开始mengbier 设\(f_u\)表示第u个点在父亲发动之后才发动的最小价 ...

  8. [暑假的bzoj刷水记录]

    (这篇我就不信有网站来扣) 这个暑假打算刷刷题啥的 但是写博客好累啊  堆一起算了 隔一段更新一下.  7月27号之前刷的的就不写了 , 写的累 代码不贴了,可以找我要啊.. 2017.8.27upd ...

  9. 退役前的做题记录2.0

    退役前的做题记录2.0 最近在刷省选题......大致上是按照省份刷的. 不过上面的题目顺序是按照写题的顺序排列的,所以可能会有点乱哈. [BZOJ2823][AHOI2012]信号塔 最小圆覆盖,随 ...

最新文章

  1. 了解C++默默编写并调用哪些函数
  2. mysql字段中去掉括号
  3. 30分钟Git命令 从入门到放弃
  4. 在一个数组中找 差值最大的两个数 差值最小的两个数 推广到 点对
  5. CSDN公众号新功能上线,居然还能搜出小姐姐???(文末有福利)
  6. android studio vfs,Android Studio:尝试呈现XML布局的InvalidVirtualFileAccessException
  7. Redis管道(Pipeline)详解
  8. 转:[kipmi0]进程导致系统负载高
  9. 电子书下载:Microsoft Windows Identity Foundation Cookbook
  10. android eclipse自动更新,Android Eclipse 升级ADT到24.0.2完美解决方案
  11. python对于设计师有什么用-《学习PYTHON—做个有编程能力的设计师》
  12. 硬件信息修改工具 支持修改机器码 硬盘 MAC 等信息
  13. 计算机软考网络工程师中级多少分过,计算机软考网络工程师中级多少分过
  14. Java分布式架构:应用+特点+架构模式
  15. 《照明设计》ASAP高级光学系统分析软件 在线 技术文章
  16. SetWindowsHookEx全局钩子
  17. ILSVRC2012数据集介绍
  18. 英文论文发表必备干货!SCI投稿7个阶段经典邮件模板,请拿走
  19. 2014年360广告算法面试经历
  20. html如何控制图片自动放缩,如何用js控制图片放大缩小

热门文章

  1. [Itanium C++ ABI] 成员指针
  2. BlueMix与商业智能BI(智慧医疗场景)
  3. keras构建卷积神经网络_在python中使用tensorflow s keras api构建卷积神经网络的初学者指南...
  4. 揭秘开一个软件公司、网络科技公司流程
  5. 基于51单片机语音播报电子秤体重秤系统设计
  6. 利用 AWS SageMaker 与英特尔 软硬件技术加快 AI 推理速度的步骤
  7. 学习用 doxygen 生成源码文档
  8. linux内核调试指南 1
  9. 20201222 Python基本数据类型
  10. 安装wampserver