您的位置:首页 > 其它

POJ 2057 The Lost House 树状DP

2011-09-29 00:35 393 查看
题意:一直小蜗牛从树顶掉了下来,但是它的壳子还留在上面。于是它有从根节点去寻找它的壳子(但是它完全忘记了之前走过的路)。在路途中有些节点上可能住着虫子,虫子可以告诉小蜗牛它之前来没来过。假如壳子在每个叶子节点上的概率相等,求出蜗牛所需要走得路程的期望。

题解:关键是确定子节点的访问顺序,使得每次访问下一个节点时重复的步数最小。那么最终的到的总遍历步数也就是最小的了。顺序一旦确定就不可以更改了,假如一个节点有5个子节点1 2 3 4 5, 访问顺序定为 3 4 1 2 5。那么蜗牛壳子在1的时候必须按这个顺序来找,壳子在2的时候也按这个顺序····壳子在5的时候还是按这个顺序。将这五种可能所花费的步数都加起来,然后除以叶子节点个数即得到答案。



#include <algorithm>
#include <iostream>
using namespace std;

#define N 1005

int next

, cnt
; /* next[i][j] 表示节点i的第j个子节点。 cnt[i]记录节点i的子节点的个数 */
bool worm
; // 记录有无虫子
int n;

struct TreeNode
{
int leaf, step1, step0; /* leaf表示该节点上的叶子节点个数。step1表示找到壳子所需步数。step0表示没找到壳子所需步数 */
} node
;

bool cmp ( int a, int b )
{
return (node[a].step0 + 2) * node[b].leaf < (node[b].step0 + 2) * node[a].leaf;
}

void dfs ( int u )
{
if ( cnt[u] == 0 )
{
node[u].leaf = 1;
node[u].step1 = node[u].step0 = 0;
return;
}

int i, v;
for ( i = 1; i <= cnt[u]; i++ )
{
v = next[u][i];
dfs ( v );
node[u].leaf += node[v].leaf;
if ( worm[v] ) node[v].step0 = 0; /* 有虫子的话,若叶子节点上没有壳子,直接返回 */
node[u].step0 += node[v].step0 + 2; /* u->v, v->u, 所以要+2 */
}

/*排序,决定访问子节点的顺序。其实就是一个贪心的过程,每次选取的节点都能使重复的次数最小。 */
sort ( next[u] + 1, next[u] + cnt[u] + 1, cmp );

int leaf = 0, sum = 0; /* sum记录访问过的子节点的失败次数之和 */
for ( i = 1; i <= cnt[u]; i++ )
{
v = next[u][i];
node[u].step1 += node[v].step1 + (sum + 1) * node[v].leaf;
sum += node[v].step0 + 2;
}
}

int main()
{
int n, x;
char ch;
while ( scanf("%d",&n) && n )
{
memset(worm,0,sizeof(worm));
memset(cnt,0,sizeof(cnt));
memset(node,0,sizeof(node));

for ( int i = 1; i <= n; i++ )
{
scanf("%d %c",&x,&ch);
if ( x != -1 )
next[x][++cnt[x]] = i;
if ( ch == 'Y' )
worm[i] = 1;
}
dfs ( 1 );
double ans = (double)node[1].step1 / node[1].leaf;
printf("%.4lf\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c