POJ 2057 The Lost House

来源:互联网 发布:imovie在mac上怎么导出 编辑:程序博客网 时间:2024/06/05 08:54

感想:基本看的是资料和解题报告才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

    \

   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 1010using namespace std;int n;struct Node {bool flag;int fa,fb,l;//fa为成功的,fb为失败,l为叶子结点的个数}T[N];vector<int> Q[N];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;}



原创粉丝点击