题目的关键是达到某个节点的时候,以怎样的顺序去遍历它的子树呢?
我们假设某个节点有两个子树A和B,我们定义Pa是Snail的Home位于A子树中的叶节点上的概率,Pb是Snail的Home位于B子树中的叶节点上的概率;Sa是Home位于A子树上所要走的路程,Fa是Home不在A子树上所要走的路程,Sb和Fb同理。假设先走A树再走B树,所走的步数为:Sa*Pa+(Fa+Sb)*Pb;如果是先走B树再走A树,所走的步数为:Sb*Pb+(Fb*Sa)*Pa。如果先走A是正确的,那一定有Sa*Pa+(Fa+Sb)*Pb<Sb*Pb+(Fb*Sa)*Pa,简化为Fa/Pa < Fb/Pb。因为Px = (x子树的叶子数)/总的叶子数,所以最后的不等式为Fa/La<Fb/Lb,Lx为x子树的叶子数。所以某个节点的子树的排序是按Fx/Lx从小到大排列的。
#include<iostream>
#include<string.h>
using namespace std;
int children[1003][10];
char state[1003];
int leaves[1003];
int dp[1003];
int calcLeaves(int now){
if(children[now][0]==0){
leaves[now] = 1;
return 1;
}
for(int i=1;i<=children[now][0];i++)
leaves[now] += calcLeaves(children[now][i]);
return leaves[now];
}
void childrenSort(int now){
for(int i=1;i<=children[now][0];i++){
int ind = i;
for(int j=i+1;j<=children[now][0];j++)
if((dp[children[now][j]]+2)*leaves[children[now][ind]] < (dp[children[now][ind]]+2)*leaves[children[now][j]])
ind = j;
if(ind != i){
int tmp = children[now][i];
children[now][i]=children[now][ind];
children[now][ind] = tmp;
}
}
}
int dfs(int now){
if(state[now]=='Y' || children[now][0]==0){
dp[now] = 0;
if(children[now][0]!=0){
for(int i=1;i<=children[now][0];i++)
dfs(children[now][i]);
childrenSort(now);
}
}
else{
dp[now]=0;
for(int i=1;i<=children[now][0];i++)
dp[now]+= dfs(children[now][i])+2;
childrenSort(now);
}
return dp[now];
}
int res = 0;
void process(int now, int step){
if(children[now][0]==0){
res += step;
return ;
}
int pre=0;
for(int i=1;i<=children[now][0];i++){
process(children[now][i],step+pre+1);
pre += dp[children[now][i]]+2;
}
}
int main()
{
int N;
while(scanf("%d",&N)&&N){
memset(children,0,sizeof(children));
for(int i=1;i<=N;i++){
int parent;
char sta;
scanf("%d %c",&parent,&sta);
if(parent != -1)
children[parent][++children[parent][0]] = i;
state[i]=sta;
}
memset(leaves,0,sizeof(leaves));
calcLeaves(1);
memset(dp,0,sizeof(dp));
dfs(1);
res = 0;
process(1,0);
printf("%.4lf\n",res*1.0/leaves[1]);
}
}