POJ 2057 The Lost House (经典树形dp)

  不错的题,做了两次。两次感觉不一样,第一次那叫一个费劲啊。。。看了一天的解题报告,才大概理解怎么回事,这次做完好好写写总结吧。

开始想到的状态有sum[i]表示以i为根的子树走遍所有的字节点的值,leaves[i]表示以i为跟的子树的叶子节点数。显然是错误的。。。好多状态表示不出来。

后来有考虑分回到i节点和不回到i节点这两种状态。但还是设计不出来,最不能确定的就是一个顺序问题。无奈翻了一下以前看的资料。发现一个没有想到的贪心方法。。。。

 success[u]表示u为根的子树上,成功找到房子的步数和

 fail[u]表示u为根的子树上,找不到房子的步数和

 leaves[u]表示u为根的子树上,叶子节点数

 如果u节点有worm,则fail[u] = 0;

   

 success[u] += (fail[u] + 1)*leave[v] + success[v];  //+1是因为要走到v子树

 fail[u] += (fail[v] + 2);    //+2表示走到又回来了。

表示u->v上,前边与u相连的所有子树都没有成功,到v子树成功找到房子的步数。

子所以要 (fail[u] + 2)*leave[v] ....这个画一下图就知道了。咳咳

 

 现在关键要解决的是按怎么样的顺序遍历u的所有字节点使得得到的success[u]最小。

显然,当(fail[u] + 1) *leave[v]越小,success[u]越小。设i,j为u的两颗子树, leave[i]越大fail[i]越小,越应该往前排(贪心),这样能保证 (fail[u] + 1)*leave[v]取的值最小

变形一下 leave[i]/fail[i] > leave[j]/fail[j];也就是说按照 leave[i]/fail[i]从大到小排序。 

bool cmp(const int u, const int v) {
  return leaves[u]*(fail[v] + 2) > leaves[v]*(fail[u] + 2);
}

 

可以先dfs遍历完u的所有子树,然后再确定顺序进行计算(注意节点为叶节点的情况。success[i] = fail[i] = 0, leaves[i] = 1)

  

  

  

   

 

 

 

    

你可能感兴趣的:(poj)