POJ 2057 The Lost House 树状DP

题意:一直小蜗牛从树顶掉了下来,但是它的壳子还留在上面。于是它有从根节点去寻找它的壳子(但是它完全忘记了之前走过的路)。在路途中有些节点上可能住着虫子,虫子可以告诉小蜗牛它之前来没来过。假如壳子在每个叶子节点上的概率相等,求出蜗牛所需要走得路程的期望。
题解:关键是确定子节点的访问顺序,使得每次访问下一个节点时重复的步数最小。那么最终的到的总遍历步数也就是最小的了。顺序一旦确定就不可以更改了,假如一个节点有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[N][N], cnt[N]; /* next[i][j] 表示节点i的第j个子节点。 cnt[i]记录节点i的子节点的个数 */
bool worm[N]; // 记录有无虫子
int n;

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

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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值