消防局的建立

本题地址:http://www.luogu.org/problem/show?pid=2279

题目描述

2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地。起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结构。如果基地A到基地B至少要经过d条道路的话,我们称基地A到基地B的距离为d。
由于火星上非常干燥,经常引发火灾,人类决定在火星上修建若干个消防局。消防局只能修建在基地里,每个消防局有能力扑灭与它距离不超过2的基地的火灾。
你的任务是计算至少要修建多少个消防局才能够确保火星上所有的基地在发生火灾时,消防队有能力及时扑灭火灾。

输入输出格式

输入格式:

输入文件名为input.txt。
输入文件的第一行为n (n<=1000),表示火星上基地的数目。接下来的n-1行每行有一个正整数,其中文件第i行的正整数为a[i],表示从编号为i的基地到编号为a[i]的基地之间有一条道路,为了更加简洁的描述树状结构的基地群,有a[i]<i。

输出格式:

输出文件名为output.txt
输出文件仅有一个正整数,表示至少要设立多少个消防局才有能力及时扑灭任何基地发生的火灾。

输入输出样例

输入样例#1:
6

1

2

3

4

5
输出样例#1:
2

这是一道蛋疼的树形DP,树形DP一般状态表示比较复杂;在题解帮助下过掉;
%大神Crazyxx
 状态:
dp[i][0]:选自己
dp[i][1]:选了至少一个儿子
dp[i][2]:选了至少一个孙子
-----------------------------------这三种是覆盖了自己的
dp[i][3]: 儿子孙子全部覆盖
dp[i][4]:孙子全部覆盖
-----------------------------------这两种并没有覆盖自己
建议画一棵深度为3的完全二叉树直观观察状态   否则转移方程比较难懂

初始转移方程:
dp[i][0] = 1+Σmin(dp[j][0...4]);
要使选了根节点之后合法(整棵子树包括根节点被覆盖)必须使儿子的孙子全部覆盖 0~4状态满足 
dp[i][1] = min( dp[k][0] + Σ(j != k)min(dp[j][0...3]) );
要使选了一个儿子之后合法 由于儿子只可以覆盖到兄弟 所以孙子一定要全部被覆盖 即儿子的儿子一定覆盖  0~3满足 
dp[i][2] = min( dp[k][1] + Σ(j != k)min(dp[j][0...2]) );
使选了一个孙子之后合法  由于孙子最多只能覆盖到当前节点 所以儿子一定全部覆盖  即所有儿子本身要被覆盖  0~2满足 
dp[i][3] = Σdp[j][0...2];
要使儿子及孙子全部被覆盖  即儿子本身要被覆盖  0~2满足 
dp[i][4] = Σdp[j][0...3]; 
 要使孙子全部被覆盖  即儿子的儿子要全部被覆盖 0~3满足
::注意每种状态由儿子转移过来所以根的情况    要转化成对于儿子来说的情况
 
然后改进状态 因为每种转移方程至少有三种可能最后取其中较小的 故时间效率较低  令dp[i][k]表示min(dp[i][0],dp[i][1]....dp[i][k])且k>=2  因为上述转移方程最少都是0~2状态
 那么转移方程就大幅度化简了:
dp[i][0] = 1+Σdp[j][4];
直接由上面变形而来 
dp[i][1] = dp[i][4] + min(dp[k][0]-dp[k][3]);
选一个儿子  需保证所有孙子被覆盖 即 dp[i][4] 然后要选出一个儿子 将他从0~3状态变为选了自己(由于dp[i][4]中他是3状态所以要减去一个dp[k][3]) 取这个差值最小的儿子
dp[i][2] = dp[i][3] + min(dp[k][1]-dp[k][2]);
 选一个孙子 与上面类似  要保证所有儿子都被覆盖 即dp[i][3] 再将一个儿子从0~2状态变为0~1状态以保证覆盖他父节点
dp[i][3] = Σdp[j][2];
保证所有儿子被覆盖  儿子的0~2状态均符合条件 
dp[i][4] = Σdp[j][3];
保证所有儿子的儿子被覆盖 儿子的0~3状态均符合条件

别问我为什么dp[i][1]和dp[1][2]用到后面的状态  因为你只需要在过程中记下那一坨min的值 把3,4处理完后再算1,2
另外由于数据特殊性 编号大的节点一定是编号小的节点的后代  所以递推顺序直接到着推就好了
代码:(神犇的代码稍作改动)

 #include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=+;
const int INF=(<<); bool G[maxn][maxn];
int dp[maxn][];
int main()
{
int n;cin>>n;
for(int i=,tmp;i<=n;i++)
{
scanf("%d",&tmp);
G[tmp][i]=;
}
for(int i = n ; i>= ; i--)
{
int x1=INF,x2=INF;
dp[ i ][ ]=;
for(int j=;j<=n;j++)
if(G[ i ][ j ])
{
dp[ i ][ ]+=dp[ j ][ ];
dp[ i ][ ]+=dp[ j ][ ];
dp[ i ][ ]+=dp[ j ][ ];
x1=min(x1,dp[ j ][ ] -dp[ j ][ ]);
x2=min(x1,dp[ j ][ ]-dp[ j ][ ]);
}
dp[ i ][ ]=dp[ i ][ ]+x1;
dp[ i ][ ]=min(dp[ i ][ ]+x2,min(dp[ i ][ ],dp[ i ][ ]));
dp[ i ][ ]=min(dp[ i ][ ],dp[ i ][ ]);
dp[ i ][ ]=min(dp[ i ][ ],dp[ i ][ ]);
}
printf("%d",dp[ ][ ]);
return ;
}

觉得做完之后对于树形DP有了新的认识 = =涨姿势了

[HNOI]2003 消防局的建立的更多相关文章

  1. [HNOI 2003]消防局的设立

    Description 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来 连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成 ...

  2. [HNOI 2003]激光炸弹

    Description 一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标.现在地图上有n个目标,用整数,表示目标在地图上的位置,每个目标都有一个价值.激光炸弹的投放是通过卫星定位的,但其 ...

  3. 【HNOI 2003】 激光炸弹

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1218 [算法] 二维前缀和 [代码] #include<bits/stdc++ ...

  4. Windows server 2003 粘滞键后门+提权

    Windows server 2003中可以建立粘滞键与cmd的连接来绕过已经设置好的安全机制做一些事情,比如新建用户.提权 粘滞键介绍 网上查了一些资料,也没怎么说明白,不如自己试一下,大概意思就是 ...

  5. FCKeditor漏洞利用

    FCKeditor漏洞利用 查看编辑器版本 FCKeditor/_whatsnew.html fckeditor/editor/dialog/fck_about.html —————————————— ...

  6. FCK编辑器漏洞总结

    1.查看编辑器版本FCKeditor/_whatsnew.html————————————————————————————————————————————————————————————— 2. Ve ...

  7. Fckeditor漏洞利用总结

    查看编辑器版本FCKeditor/_whatsnew.html——————————————————————————————————————————————————————— —————— 2. Ver ...

  8. oracle管理优化必备语句以及oracle SQL语句性能调整

    本文转自http://www.dataguru.cn/article-3302-1.html oracle数据库管理优化必备语句: 1. SELECT T.START_TIME,T.USED_UBLK ...

  9. Fckeditor常见漏洞的挖掘与利用整理汇总

    查看编辑器版本号 FCKeditor/_whatsnew.html ------------------------------------------------------------- 2. V ...

随机推荐

  1. POJ 2629:Common permutation

    Common permutation Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5510   Accepted: 168 ...

  2. 关于Flask的默认session

    Flask的默认session利用了Werkzeug的SecureCookie,把信息做序列化(pickle)后编码(base64),放到cookie里了. 过期时间是通过cookie的过期时间实现的 ...

  3. NOIP 2013 花匠 神仙操作

    题目:https://www.luogu.org/problemnew/show/P1970 今天又学习了一个新的神仙操作: 标签是DP,想了一下,没什么心情写,默默打开题解——(狂喜!) 一位大佬( ...

  4. va_start和va_end使用详解(转载)

    转自:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html 本文主要介绍va_start和va_end的使用及原理. 在以前 ...

  5. 在visual studio code和visual studio中编写TypeScript文件自动生成JavaScript文件

    注:此处的自动生成都为保存ts文件时自动生成js文件 VS CODE 只需要在TypeScript的终端控制台中输入如下命令即可,并注意需要将其中的*换成对应的文件名,此处的*似乎不能作为通用匹配. ...

  6. bzoj 1653: [Usaco2006 Feb]Backward Digit Sums【dfs】

    每个ai在最后sum中的值是本身值乘上组合数,按这个dfs一下即可 #include<iostream> #include<cstdio> using namespace st ...

  7. bzoj 1649: [Usaco2006 Dec]Cow Roller Coaster【dp】

    DAG上的dp 因为本身升序就是拓扑序,所以建出图来直接从1到ndp即可,设f[i][j]为到i花费了j #include<iostream> #include<cstdio> ...

  8. bzoj 1638: [Usaco2007 Mar]Cow Traffic 奶牛交通【记忆化搜索】

    震惊!记忆化搜索忘记返回map值调了半小时! 边(u,v)的经过次数是:能到u的牛数*v到n的方案数.正反两次连边,dfs两次即可 #include<iostream> #include& ...

  9. git分支的理解

    分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN. 如果两个平行宇宙互不干扰,那对现在的你也没啥影响.不过,在某个时间点,两个平行宇宙合并 ...

  10. ROS-URDF仿真

    前言:URDF (标准化机器人描述格式),是一种用于描述机器人及其部分结构.关节.自由度等的XML格式文件. 一.首先做一个带有四个轮子的机器人底座. 1.1 新建urdf文件 在chapter4_t ...