您的位置:首页 > 其它

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前失败的步数).

继续:



  可以看到  若将 子节点 

 位置改变, 则对于公式 后两项没有影响,

  所以对于 子节点

 间位置关系, 我们仅需考虑第一项就可以了

    令

      

 为 两子节点 

 顺序放置时 值。

      

为 两子节点 

 交换放置时 值。

    则 两值做差 得到:

      


           所以我们得出结论,

 顺序位置 则只跟元素

 的信息有关,于别的元素的排列情况无关,所以元素

 是可比的。
           
/*
真心把我虐得好惨,一看题目就傻眼了,搞了半天看懂题意发现完全超出自己的实力之外,然后去看黄劲松写的《贪婪的动态规划》,我靠,
发现完全就是纯数学,搞了一下午就看懂了这个推理(里面一句话将我困住半天,真希望这些大神们写点注释)
 */
#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: