POJ 2057 - The Lost House

设一棵树有两个子树A,B。Pa是房子在A子树上的概率,Pb是房子在B子树上的概率。

先走A子树寻找房子的期望是:

【在A子树上找到房子的路程】*Pa+(【没有在A子树上找到房子的路程(固定的一个值)】+【在B子树上找到房子的路程】)*Pb。  

先走B子树寻找房子的期望是:

【在B子树上找到房子的路程】*Pb+(【没有在B子树上找到房子的路程(固定的一个值)】+【在A子树上找到房子的路程】)*Pa。

若这两个值做比较的话,可以化简为:

【没有在A子树上找到房子的路程(固定的一个值)】*Pb【没有在B子树上找到房子的路程(固定的一个值)】*Pa相比较。

Pa=(A子树上的叶子节点数)/(所有的叶子节点数);Pb也是如此。

通过排序就可以设计出在树上的寻找路径了。

——引用来自http://blog.csdn.net/lin375691011/article/details/31446343

当然,由于所有的叶子结点数目是固定的,所以可以直接用A子树上的叶子节点数代替Pa,类似的Pb也是如此。

对于表示u为根的子树上,找不到房子的步数和dp[u][0]=∑(dp[v][0]+2)  ( (u,v)是一条边,因为是没找到,所以永远都要从哪里出发就回到那里,所以每多一层,就多一次去加一次来 )

 (真的是一道非常不错的题目,值得深究)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define MAXN 1005
 5 using namespace std;
 6 int n,num[MAXN],dp[MAXN][2],head[MAXN];
 7 //dp[u][1]:表示u为根的子树上,成功找到房子的步数和 
 8 //dp[u][0]:表示u为根的子树上,找不到房子的步数和 
 9 //head[u]:第一条以u为头节点的边
10 bool worm[1005];
11 struct Edge{
12     int u,v,adj;//起点、终点、同起点的邻边 
13 }edge[MAXN];
14 bool cmp(int a,int b)
15 {
16     return( (dp[a][0]+2)*num[b] < (dp[b][0]+2)*num[a] );
17 }
18 void dfs(int st)
19 {
20     int p=head[st];
21     dp[st][0]=0;
22     dp[st][1]=0;
23     num[st]=0;
24     if(p==-1) num[st]++;//作为根,本身就是叶子结点 
25     else
26     {
27         int cnt=0,group[10];
28         while(p!=-1)
29         {
30             dfs(edge[p].v);
31             dp[st][0]+=dp[(edge[p].v)][0]+2;
32             num[st]+=num[edge[p].v];
33             group[cnt++]=edge[p].v;
34             p=edge[p].adj;
35         }
36         if(worm[st]) dp[st][0]=0;//如果有worm帮忙,知道这里从这里往下不用再找了,没有房子,就不用跑 
37         sort(group,group+cnt,cmp);
38         int tmp=0;
39         for(int i=0;i<cnt;i++)//i表示在第i棵子树下有房子 
40         {
41             dp[st][1]+=dp[group[i]][1]+(tmp+1)*num[group[i]];
42             tmp+=dp[group[i]][0]+2;//走了i子树,没有找到,返回到st 
43         }//这一段for语句非常漂亮,属于解本题的核心思路
44     } 
45     //printf("point %d: dp[][0]=%d dp[][1]=%d\n",st,dp[st][0],dp[st][1]);
46 }
47 int main()
48 {
49     while(scanf("%d",&n) && n!=0)
50     {
51         memset(head,-1,sizeof(head));
52         int from,cnt=1;
53         char tmp[5];
54         scanf("%d%s",&from,tmp);
55         for(int i=2;i<=n;i++)
56         {
57             scanf("%d%s",&from,tmp);
58             worm[i]=(tmp[0]=='Y'?1:0);
59             edge[cnt].u=from; 
60             edge[cnt].v=i;
61             edge[cnt].adj=head[from];
62             head[from]=cnt;
63             cnt++;
64         }
65         /*
66         for(int i=1;i<=n-1;i++) printf("edge %d: from=%d to=%d adj=edge%d\n",i,edge[i].u,edge[i].v,edge[i].adj);
67         for(int i=1;i<=n;i++) printf("head %d: edge %d\n",i,head[i]); //检查边是否存储正确 
68         for(int i=2;i<=n;i++) printf("point %d: worm %s\n",i,worm[i]?"exist":"not exist"); //检查worm是否存储正确
69         */
70         dfs(1); 
71         printf("%.4f\n", ((double)dp[1][1])/((double)num[1]) );
72     }
73 }

另外,请注意http://poj.org/showmessage?message_id=341806,这影响到输入时的数据存储方式,之前我是按照:边是按顺序一层层下来的,就一直WA

posted @ 2017-06-15 13:06  Dilthey  阅读(220)  评论(0编辑  收藏  举报