POJ 2057 The Lost House
2013-08-01 16:52
281 查看
感想:基本看的是资料和解题报告才A出来的,实话说,这题真心不是树形dp的入门题,不骂人,和谐。 详情请参考黄劲松的《贪婪的动态规划》 ,如果没找到的话可以留言,我发给你。
题意:蜗牛的房子遗失在了一棵树的某个叶子结点上,它要从根结点出发开始寻找它的房子。有一些中间结点可能会住着一些虫子,这些虫子会告诉蜗牛它的房子是否在以这个中间结点为根的子树上,这样蜗牛就不用白跑路了。当然,如果有些结点没有住着虫子的话,那么可怜的蜗牛只有靠自己决定访问顺序来探索了。假设蜗牛走过一条边的耗费都是1,且房子遗失在每个叶子结点的概率都是相等的,请算出蜗牛找到他的房子的最小数学期望值。(就这么几句话,竟然这么一大篇英文)
思路: fb[i]表示蜗牛不在i为根的子树上的时候遍历该子树需要的时间
fa[i]表示蜗牛的房子在i为根的子树上的期望和。 l[i]表示以i为根的子树上叶子节点的数目
题目的答案即为 : fa[root]/l[root];
u的孩子节点依次为s[1].......s[k]
fa[u]的计算方式为:fa[\u] = 0; fb[u] = 0;
for(i=1 to k) //这里的值还需要有子节点遍历的顺序来决定
{
① fa[u] = fa[u] + (fb[u]+1)*l[s[i]]+fa[s[i]] //这里的fb[u]一直在更新,只是表示遍历前面子节点需要的时间
②fb[u] = fb[u] + fb[s[i]] + 2
}
②的形式大家应该都懂,主要是①,
转自风炎大神:所以得出Success[father]=(Failure[father]+1)*Leaves[k]+Success[k]。比较费解的就是用红色标出的那部分了。
先看图(用的是题目中的例子):
1
/ \
2 3(4)
/ \
4(1) 5(3)
先假设3为根,那么遍历4和5的步数1+3=4;那么如果1是根,这时要遍历4和5的步数是2+4=6,多一条边,使到4到的步数从1变为2,使到5的步数从3变为4。加起来就比原来多了2。也就是说如果有N个叶结点的话,那么应该多1*N步了。那么如果先从1到2,再从2回到1,之后再走呢。这时应该多了failure[1到2]*N步了。这就解释了红色那部分(红色中的那个failure[father]从代码中可以看出是走K前失败的步数).
继续:
可以看到 若将 子节点
位置改变, 则对于公式 后两项没有影响,
所以对于 子节点
间位置关系, 我们仅需考虑第一项就可以了
令
为 两子节点
顺序放置时 值。
为 两子节点
交换放置时 值。
则 两值做差 得到:
所以我们得出结论,
顺序位置 则只跟元素
的信息有关,于别的元素的排列情况无关,所以元素
是可比的。
题意:蜗牛的房子遗失在了一棵树的某个叶子结点上,它要从根结点出发开始寻找它的房子。有一些中间结点可能会住着一些虫子,这些虫子会告诉蜗牛它的房子是否在以这个中间结点为根的子树上,这样蜗牛就不用白跑路了。当然,如果有些结点没有住着虫子的话,那么可怜的蜗牛只有靠自己决定访问顺序来探索了。假设蜗牛走过一条边的耗费都是1,且房子遗失在每个叶子结点的概率都是相等的,请算出蜗牛找到他的房子的最小数学期望值。(就这么几句话,竟然这么一大篇英文)
思路: fb[i]表示蜗牛不在i为根的子树上的时候遍历该子树需要的时间
fa[i]表示蜗牛的房子在i为根的子树上的期望和。 l[i]表示以i为根的子树上叶子节点的数目
题目的答案即为 : fa[root]/l[root];
u的孩子节点依次为s[1].......s[k]
fa[u]的计算方式为:fa[\u] = 0; fb[u] = 0;
for(i=1 to k) //这里的值还需要有子节点遍历的顺序来决定
{
① fa[u] = fa[u] + (fb[u]+1)*l[s[i]]+fa[s[i]] //这里的fb[u]一直在更新,只是表示遍历前面子节点需要的时间
②fb[u] = fb[u] + fb[s[i]] + 2
}
②的形式大家应该都懂,主要是①,
转自风炎大神:所以得出Success[father]=(Failure[father]+1)*Leaves[k]+Success[k]。比较费解的就是用红色标出的那部分了。
先看图(用的是题目中的例子):
1
/ \
2 3(4)
/ \
4(1) 5(3)
先假设3为根,那么遍历4和5的步数1+3=4;那么如果1是根,这时要遍历4和5的步数是2+4=6,多一条边,使到4到的步数从1变为2,使到5的步数从3变为4。加起来就比原来多了2。也就是说如果有N个叶结点的话,那么应该多1*N步了。那么如果先从1到2,再从2回到1,之后再走呢。这时应该多了failure[1到2]*N步了。这就解释了红色那部分(红色中的那个failure[father]从代码中可以看出是走K前失败的步数).
继续:
可以看到 若将 子节点
位置改变, 则对于公式 后两项没有影响,
所以对于 子节点
间位置关系, 我们仅需考虑第一项就可以了
令
为 两子节点
顺序放置时 值。
为 两子节点
交换放置时 值。
则 两值做差 得到:
所以我们得出结论,
顺序位置 则只跟元素
的信息有关,于别的元素的排列情况无关,所以元素
是可比的。
/* 真心把我虐得好惨,一看题目就傻眼了,搞了半天看懂题意发现完全超出自己的实力之外,然后去看黄劲松写的《贪婪的动态规划》,我靠, 发现完全就是纯数学,搞了一下午就看懂了这个推理(里面一句话将我困住半天,真希望这些大神们写点注释) */ #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define N 1010 using namespace std; int n; struct Node { bool flag; int fa,fb,l;//fa为成功的,fb为失败,l为叶子结点的个数 }T ; vector<int> Q ; bool cmp(int x,int y) { return ((T[x].fb+2)*T[y].l < (T[y].fb+2)*T[x].l);//贪心的顺序 } void dfs(int u) { for(int i=0;i<Q[u].size();++i) dfs(Q[u][i]); T[u].fa = T[u].fb = T[u].l = 0; if(Q[u].size()==0) T[u].l = 1; if(Q[u].size() > 0) { sort(Q[u].begin(),Q[u].end(),cmp); for(int i=0;i<Q[u].size();++i) { int v = Q[u][i]; T[u].fa += (T[u].fb+1)*T[v].l + T[v].fa; T[u].fb += T[v].fb + 2; T[u].l += T[v].l; } if(T[u].flag) T[u].fb = 0; } } int main(void) { while(cin>>n,n) { for(int i=1;i<=n;++i) Q[i].clear(); for(int i=1;i<=n;++i) { char ch; int tmp; scanf("%d %c",&tmp,&ch); if(tmp!=-1)//-1表示的是root { Q[tmp].push_back(i); } T[i].flag = (ch=='N'?false:true); } dfs(1); double ans = 1.0*T[1].fa/T[1].l; printf("%.4llf\n",ans); } return 0; }
相关文章推荐
- poj 2057 The Lost House
- POJ-2057 The Lost House 贪心在动态规划中的应用
- POJ 2057 The Lost House
- poj 2057 The Lost House 贪心思想在动态规划上的应用
- POJ 2057 The Lost House
- POJ 2057 The Lost House 树形DP+贪心
- POJ 2057 The Lost House
- POJ 2057 The Lost House 经典树形DP+贪心
- POJ 2057 The Lost House 树形DP+贪心
- POJ 2057 The Lost House (经典树形dp)
- poj 2057 The Lost House
- poj 2057 The Lost House
- POJ 2057 The Lost House
- POJ 2057 The Lost House
- POJ 2057 The Lost House 树状DP
- poj_2057 The Lost House(树形dp)
- 【树形DP】【poj 2057】The Lost House
- POJ 2057 The Lost House [树状DP]
- POJ 2057 The lost house
- POJ 2057 The Lost House