题意:一只蜗牛将壳忘在了一棵树的某一个末结点(叶子)上。它想找回自己的壳,但忘记是丢在哪个结点上了,只好从树根开始网上爬,一个结点一个结点地找。在一些结点上居住着毛毛虫,它们会告诉蜗牛该结点以及它的子树上是否有它的壳,这样可以节省些时间。两个结点如果相连,则距离为1。问蜗牛找到壳的最小期望距离为多少。

接着给了一个例子(上图):

  假如蜗牛以结点2,4,5的顺序找,则壳分别在结点2,4,5时它需要爬行的距离为1,4,6。则它找到壳的期望为(1 + 4 + 6) / 3 = 11/3。

  考虑另一种情况,假设蜗牛先往结点3的方向爬,而在结点3处有毛毛虫,它可以告诉毛毛虫有关壳的信息,如果壳不在结点3和它的子树上,蜗牛就可以直接调转方向去2了。则以结点4,5,2的遍历顺序来考虑,它需要爬行的距离分别为2, 4, 3,则期望为(2 + 4 + 3) / 3 = 3。该例子中3即为最小期望距离。

思路:

  该题真的很锻炼思维呀,脑细胞死了不少。。

  首先需要用一个leaf[]数组来存储某节点子树上的叶子数,如上图,leaf[1] = 3, leaf[3] = 2。

  此外,对于某结点x,壳只可能有两种状态:在或者不在结点x的子树上。因此,用success[x]表示当壳在结点x的子树上时蜗牛在子树每个叶子上分别找到壳的爬行距离(距离0是从结点x开始算起)之和,如上图,success[3] = 1 + 3;当先访问结点3时,success[1] = 2 + 4 + 3。 这里与上面例子的期望的计算过程对比可以看出,当success表示的值总为最优情况下的距离时,最终期望即为success[1] / leaf[1]。当x为叶子结点时,success[x] = 0。

  当然,我们还要考虑在结点x的子树上找不到壳的情况,用fail[x]表示蜗牛在子树每个叶子上分别没有找到壳时的爬行距离(距离0是从结点x开始算起)之和,该值也应是最优的。最优体现在:如果x处有一只毛毛虫,而且提示x的子树上没有壳时,或者x结点为叶子时,蜗牛便不会再继续前进了,此时fail[x] = 0;否则,蜗牛就只好往前摸索了,此时fail[x] = sum(fail[y] + 2)。其中y是x的儿子结点。还是以上图为例,对于结点3来说,假如此处没有毛毛虫且壳不在3的子树上时,fail[3] = (fail[4] + 2) + (fail[5] + 2)。每个结点都要加2,是因为还要算上折返的距离。比如对于fail[4],蜗牛还要爬过边<3, 4>和<4, 3>,其他结点同理。

  问题的重点是,如何得出每一个点的success值。

  依然是先从简单的开始考虑,先不考虑让success最优。对于结点x,先将它的儿子结点按照遍历顺序从1开始编号,假设目前要遍历的为结点i,则结点1到(i-1)都已经遍历过了,且它们的子树上都没有壳。这里在计算success[x]的同时也在计算fail[x]。每遍历完一个儿子结点y时就有 fail[x] += fail[y] + 2。则当目前要遍历的结点为i时,fail[x]中恰好存储的是访问过结点1到(i-1)且都没有找到壳时的总距离。此时递推公式就比较好理解了:

  success[x] += (fail[x] + 1) * leaf[i] + success[i]。

  需要理解的是,success[i]表示的为结点i子树上找到壳的总距离,该距离是从结点i开始算起的。如果想将该距离转化为以结点x为起点,则需要加上在访问结点i之前走过的总路程,该总路程即为fail[x] + 1。蜗牛找完结点i-1后回到了x,然后从x爬向结点i,这里的加1即为边<x, i>的长度。此外,还需要考虑到结点i的子树上有不止一片叶子,则对于每一片叶子,在访问i之前都爬过了fail[x] + 1的距离,所以需要增加的总距离为(fail[x] + 1) * leaf[i]。

  现在,将最优的前提也考虑进去,则对于结点x,其儿子的访问顺序将会决定是否最优。

  假设x的其中两个儿子为y1, y2。

  如果先y1后y2的顺序遍历到y2,此时有:

  Δsuccess1 = (fail[x] + 1) * leaf[y1] + success[y1] + (fail[x] + fail[y1] + 2 + 1) * leaf[y2] + success[y2];

  如果先y2后y1的顺序遍历到y1,此时有:

  Δsuccess2 = (fail[x] + 1) * leaf[y2] + success[y2] + (fail[x] + fail[y2] + 2 + 1) * leaf[y1] + success[y1];

  Δsuccess1 - Δsuccess2 = (fail[y1] + 2) * leaf[y2] - (fail[y2] + 2) * leaf[y1]。

  这里用到了贪心,对于结点x,如果想让success[x]为最优,则每次遍历时取的儿子结点都应让success[x]的增量为最小。实现的方法是,当访问到结点x时,先用sort函数对x的所有儿子结点排序,排序的规则就是上面那个增量差值的公式,增量小的在前,然后依次遍历,这样得到的success[x]即为最优。

  写了这么多,自己都觉得有些絮叨。这两天脑子昏昏沉沉的,这道题找别人题解看了两天,才渐渐想明白,因此就在这里一点点地分析思路,也是为了帮助向我一样做这题怎么想都想不明白的人吧。

  此外,可能看上面的分析觉得很复杂,但如果看看代码,会觉得简单且好理解不少。有时候看文字解释,真不如读两行代码来得明白。

 

 #include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<iostream>
#define maxn 1005
using namespace std; int su[maxn], fail[maxn], le[maxn], n, root;
bool w[maxn];
vector<int> a[maxn];
bool cmp(int x,int y)
{
return (fail[x] + ) * le[y] < (fail[y] + ) * le[x];
}
void dp(int x)
{
if (a[x].empty())
{
le[x] = ;
return;
}
for (int i = ; i < a[x].size(); i++)
{
int y = a[x][i];
dp(y);
le[x] += le[y];
}
sort(a[x].begin(), a[x].end(), cmp);
for (int i = ; i < a[x].size(); i++)
{
int y = a[x][i];
su[x] += (fail[x] + ) * le[y] + su[y];
fail[x] += fail[y] + ;
}
if (w[x]) fail[x] = ;
}
int main()
{
//freopen("data.in", "r", stdin);
while (~scanf("%d", &n) && n)
{
memset(fail, , sizeof(fail));
memset(su, , sizeof(su));
memset(le, , sizeof(le));
memset(w, , sizeof(w));
for (int i = ; i <= n; i++)
a[i].clear();
for (int i = ; i <= n; i++)
{
int j;
char ch;
scanf("%d %c", &j, &ch);
if (j == -) root = i;
else a[j].push_back(i);
w[i] = (ch == 'Y' ? : );//w[i]表示该结点是否有毛毛虫
}
dp(root);
printf("%.4lf\n", . * su[root] / le[root]);
}
return ;
}

POJ 2057 The Lost House [树状DP]的更多相关文章

  1. poj 2342 Anniversary party_经典树状dp

    题意:Ural大学有n个职员,1~N编号,他们有从属关系,就是说他们关系就像一棵树,父节点就是子节点的直接上司,每个职员有一个快乐指数,现在要开会,职员和职员的直接上司不能同时开会,问怎才能使开会的快 ...

  2. POJ 1655 Balancing Act (树状dp入门)

    Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any nod ...

  3. 树状DP (poj 2342)

    题目:Anniversary party 题意:给出N各节点的快乐指数,以及父子关系,求最大快乐指数和(没人职员愿意跟直接上司一起玩): 思路:从底向上的树状DP: 第一种情况:第i个员工不参与,F[ ...

  4. poj3659树状DP

    Cell Phone Network Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6273   Accepted: 225 ...

  5. hdu 1561 The more, The Better_树状dp

    题目链接 题意:给你一棵树,各个节点都有价值(除根节点),从根节点出发,选择m个节点,问最多的价值是多小. 思路:很明显是树状dp,遍历树时背包最优价值,dp[i][k]=max{dp[i][r]+d ...

  6. 树状DP HDU1520 Anniversary party

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520 题意:职员之间有上下级关系,每个职员有自己的happy值,越高在派对上就越能炒热气氛.但是必须是 ...

  7. [Codeforces743D][luogu CF743D]Chloe and pleasant prizes[树状DP入门][毒瘤数据]

    这个题的数据真的很毒瘤,身为一个交了8遍的蒟蒻的呐喊(嘤嘤嘤) 个人认为作为一个树状DP的入门题十分合适,同时建议做完这个题之后再去做一下这个题 选课 同时在这里挂一个选取节点型树形DP的状态转移方程 ...

  8. HDU 4714 Tree2cycle(树状DP)(2013 ACM/ICPC Asia Regional Online ―― Warmup)

    Description A tree with N nodes and N-1 edges is given. To connect or disconnect one edge, we need 1 ...

  9. poj2486--Apple Tree(树状dp)

    Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7789   Accepted: 2606 Descri ...

随机推荐

  1. 【java】实体类中 Set<对象> 按照对象的某个字段对set排序

    Java利用hibernate进行一对多查询时,把另一张表作为一个属性存进这张表的字段中,返回的类型是set类型,要对返回的set类型进行排序 user表 package onlyfun.caterp ...

  2. opencv使用日记之一:平台搭建Mat类以及图像的读取修改

    平台搭建就摸了一整天时间,真的是...不说了,最后我选择的是 opencv3.0(2015/06/04)  + win7 + vs2012   注意opencv的版本不同导入的库文件是不一样的,所以请 ...

  3. CodeForces 781E Andryusha and Nervous Barriers 线段树 扫描线

    题意: 有一个\(h \times w\)的矩形,其中有\(n\)个水平的障碍.从上往下扔一个小球,遇到障碍后会分裂成两个,分别从障碍的两边继续往下落. 如果从太高的地方落下来,障碍会消失. 问从每一 ...

  4. day09 threading, paramiko, queue 模块

    1 模拟ssh 2 锁 内部锁,程序锁,信号量 3 多线程 4  简单消息队列 先来看模拟ssh  ,python 的强大之处就是因为有很多模块,可以很简单的完成复杂的事情,今天我们用paramiko ...

  5. 【网易严选】iOS持续集成打包(Jenkins+fastlane+nginx)

    本文来自网易云社区 作者:孙娇 严选iOS客户端的现有打包方式是通过远程连接打包机执行脚本去打包,打完包会输出相应的ipa的二维码,扫一扫二维码可以安装,但是随着测试队伍的壮大,外包同学越来越多,在打 ...

  6. 【Reverse Integer】cpp

    题目: Reverse digits of an integer. Example1: x = 123, return 321Example2: x = -123, return -321 click ...

  7. Pycharm注册码最新版本2019激活码activation code + 最实用的激活方法(亲测有效)

    同时适用于jetbrains全系列可用例:IDEA.WebStorm.phpstor 由于想趁着这个寒假多学习下python,所以这些实用小技巧分享给大家,拿走不谢~ 这里为大家提供了两种最实用的激活 ...

  8. Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发

    接入微信公众平台开发,开发者需要按照如下步骤完成: 1.填写服务器配置 2.验证服务器地址的有效性 3.依据接口文档实现业务逻辑 资料准备: 1.一个可以访问的外网,即80的访问端口,因为微信公众号接 ...

  9. MySQL主从复制入门

    1.MySQL主从复制入门 首先,我们看一个图: MySQL 主从复制与读写分离概念及架构分析 影响MySQL-A数据库的操作,在数据库执行后,都会写入本地的日志系统A中. 假设,实时的将变化了的日志 ...

  10. [python][django 1.10中文文档]

    https://docs.djangoproject.com/en/1.10/  官方文档,点我下载 推荐一个翻译django 1.8.2的网址: 推荐一个翻译django 1.10的博客:(着重推荐 ...