数据结构与算法实验题6.1 s_sin’s bonus byFZuer

         玩家从n 个点n-1 条边的图,从节点1 丢下一个小球,小球将由于重力作用向下落,而
从小球所在点延伸出的每一条边有一个值pi 为小球通过该条边的概率(注意从同一个节点
向下延伸的所有边的pi 的和可以小于1,也可以大于1,并且保证对于单独的一条边不会出
现pi>1 的情况),而对于所有处于最下方的节点(如图红点所示)都可以有一个值vi,代
表玩家可以获得的奖励。现在老板给你这样一张图,之后给你n 个vi 的值,老板希望玩家
可以获得的奖励的期望值最小。(对题目不理解可以参见样例)
Ps:小球不会逆着重力往回滚QAQ。保证所给出的图无重边。
★数据输入
输入第一行为一个正整数N (2 < N < 10000), 表示有n 个节点,编号为1 到N。
接下来N-1 行,每行三个整数a b pi ,表示从a,b 之间有一条路径,经过这条路径的
可能性为pi。
接下来一行为有n 个整数,表示n 个vi 的值(10000>=vi>0)。
★数据输出

输入第一行为一个正整数N (2 < N < 10000), 表示有n 个节点,编号为1 到N。
接下来N-1 行,每行三个整数a b pi ,表示从a,b 之间有一条路径,经过这条路径的
可能性为pi。
接下来一行为有n 个整数,表示n 个vi 的值(10000>=vi>0)。
★数据输出
对于每个询问,输出一行一个数精度要求为.10lf,表示最小的奖励期望值。
输入示例输出示例
7

1 2 0.8
1 3 0.2
2 4 1.0
4 7 1.0
3 5 0.7
3 6 0.3
1 2 3 4 5 6 7
1.2600000000

 

表示题目看了好久才懂~(最后的n个vi值不一定全部需要用到,根据建立的二叉树,才能确定需要用到多少个)

开始没弄懂父节点数组表示法,按照自己的思路做,写了一个好搞笑的代码,然后又尝试用孩子链表表示法做还是行不通,然后又认真研究了一下父节点数组表示法,看到这个代码,顿时豁然开朗:

  1 #include <iostream>
  2 using namespace std;
  3 
  4 #define MAX_TREE_SIZE 100
  5 typedef struct     //节点结构
  6 {
  7     char data;
  8     int parent;        //双亲位置域
  9 }PTNode;
 10 
 11 typedef struct        //树结构
 12 {
 13     PTNode node[MAX_TREE_SIZE];
 14     int count;        //根的位置和节点个数
 15 }PTree;
 16 
 17 //初始化树
 18 void init_ptree(PTree &tree)
 19 {
 20     tree.count=-1;
 21 }
 22 //添加节点
 23 void add_ptnode(PTree &tree, PTNode ptnode)
 24 {
 25     tree.count++;
 26     tree.node[tree.count].data = ptnode.data;
 27     tree.node[tree.count].parent = ptnode.parent;
 28 }
 29 //输出树
 30 void print_ptree(PTree &tree)
 31 {
 32     int i;
 33     for(i=0;i<=tree.count;i++)
 34     {
 35         cout<<"   "<<i<<"        "<<tree.node[i].data<<"        "<<tree.node[i].parent<<endl;
 36     }
 37 }
 38 //前序遍历
 39 void PreOrder(PTree &tree , int num)
 40 {
 41     for(int i=num; i<=tree.count; i++)
 42     {
 43            if(i == num)
 44            {
 45                 cout<<"   "<<i<<"        "<<tree.node[i].data<<"        "<<tree.node[i].parent<<endl;
 46                 for(int j=num+1 ; j<=tree.count; j++)
 47                 {
 48                      if(tree.node[j].parent == i)
 49                      {
 50                         PreOrder(tree , j);
 51                      }
 52                 }
 53            }
 54     }
 55 }//PreOrder
 56 //树没有中序遍历
 57 //后序遍历
 58 void BackOrder(PTree &tree , int num)
 59 {
 60     for(int i=num; i<=tree.count; i++)
 61     {
 62            if(i == num)
 63            {
 64                 for(int j=num+1 ; j<=tree.count; j++)
 65                 {
 66                      if(tree.node[j].parent == i)
 67                      {
 68                         BackOrder(tree , j);
 69                      }
 70                 }
 71                 cout<<"   "<<i<<"        "<<tree.node[i].data<<"        "<<tree.node[i].parent<<endl;
 72                 
 73            }
 74     }
 75 }//BackOrder
 76 
 77 int main()
 78 {
 79     FILE *fin=fopen("树的表示法.txt","r");
 80 
 81     PTree ptree;
 82     init_ptree(ptree);
 83     PTNode ptnode;
 84 
 85     while(fscanf(fin,"%c%d",&ptnode.data,&ptnode.parent)!=EOF)
 86     {
 87         add_ptnode(ptree,ptnode);
 88         fscanf(fin,"%c%d",&ptnode.data,&ptnode.parent);
 89     }
 90     //输出树
 91     cout<<"数组下标  节点值  双亲位置"<<endl;
 92     print_ptree(ptree);
 93 
 94 
 95     //前序遍历
 96     //cout<<endl;
 97     //PreOrder(ptree,0);
 98 
 99     //后序遍历
100     //cout<<endl;
101     //BackOrder(ptree,0);
102 
103     fclose(fin);
104     return 0;
105 }
View Code

根据父节点建立的二叉树算法思路,自己写了下面的代码,关键在于后续遍历中,找最后根结点的算法!想了好久,最后还是从数据中找到了规律:

 1 #include<stdio.h>
 2 
 3 double ans=0.0,a[10001];
 4 int t=0;
 5 
 6 typedef struct     
 7 {
 8     double data;       //数据域
 9     int parent;        //父节点位置
10 }PTNode;
11 
12 typedef struct        
13 {
14     PTNode node[10001];  //根结构
15     int count;        //根的结点个数
16 }PTree;
17 
18 PTree ptree;
19 PTNode ptnode;
20 
21 
22 void add_ptnode(int x1,int x2,double pro)
23 {
24     ptree.node[x2].parent=x1;               //储存结点的父节点
25     ptree.node[x2].data=pro*ptree.node[x1].data;//计算权值
26 }
27 
28 
29 
30 void BackOrder(PTree tree,int num)//后序遍历,递归实现
31 {
32     int i,j;
33     i=num;
34     if(i<=tree.count)
35     {
36         for(j=num+1;j<=tree.count;j++)
37         {
38             if(tree.node[j].parent==i)//找到该节点的子节点
39             {    
40                 BackOrder(tree,j);      //子节点作为新的父节点,向下递归
41                 if((j+i)>tree.count)     //分支最低结点算法,判断为(i+j>tree,count)
42                 {
43                     ans+=(a[t]*tree.node[j].data);
44                     t++;
45                     
46                 }
47                 
48             }
49         }
50         
51     }
52     
53 }
54 
55 int main()
56 {
57     int n,i,sit_1,sit_2;
58     double pro;  
59     scanf("%d",&n);
60     ptree.count=n;
61     for(i=1;i<=n;i++)
62     {
63         ptree.node[i].data=1;
64     }
65     
66     for(i=0;i<n-1;i++)
67     {
68         scanf("%d %d %lf",&sit_1,&sit_2,&pro);
69         add_ptnode(sit_1,sit_2,pro);
70     }
71     
72     for(i=0;i<n;i++)
73     {
74         scanf("%lf",&a[i]);
75     }
76     
77     BackOrder(ptree,1);
78     printf("%.10lf\n",ans);
79     
80     return 0;
81 }
View Code

做题找对算法真的很重要!!!

 最终提交代码 修改日期:2013-10-29 15:01:21

  1 #include<stdio.h>
  2 #include<iostream>
  3 #include<algorithm>
  4 using namespace std;
  5 
  6 struct PNnode
  7 {
  8     double data;//数据域
  9     int parents;
 10 };
 11 
 12 struct PTree  
 13 {
 14     PNnode node[10001];
 15     int count;//节点数
 16 };
 17 
 18 PTree ptree;
 19 PNnode pnode;
 20 double ans=0.0,a[10001],b[10001];
 21 int t=0;
 22 
 23 int f[10001]={0};
 24 
 25 
 26 void insert(int x1,int x2,double pro)//插入父节点
 27 {
 28     ptree.node[x2].parents=x1;
 29     ptree.node[x2].data=pro;
 30     f[x1]=1;
 31 }
 32 
 33 
 34 /*void search(PTree pt,int n)
 35 {
 36     for(int i=n;i<=pt.count;i++)
 37     {
 38         if(i==n)
 39         {
 40             for(int j=n+1;j<=pt.count;j++)
 41             {
 42                 if(pt.node[j].parents==i)
 43                 {
 44                     pt.node[j].data=pt.node[j].data*pt.node[i].data;
 45                     if(f[j]==0)
 46                     {
 47                         b[t]=pt.node[j].data;
 48                         t++;
 49                     }
 50                     search(pt,j);
 51                 }
 52             }
 53             
 54         }
 55     }
 56 }*/
 57 
 58 int main()
 59 {
 60     int n,i,sit_1,sit_2;
 61     double pro;
 62     f[1]=1;
 63     scanf("%d",&n);
 64     ptree.count=n;
 65 
 66     for(i=0;i<=n;i++)//初始化data
 67         ptree.node[i].data=1.0;
 68 
 69     for(i=0;i<n-1;i++)
 70     {
 71         scanf("%d %d %lf",&sit_1,&sit_2,&pro);
 72         insert(sit_1,sit_2,pro);
 73     }
 74     for(i=0;i<n;i++)
 75         scanf("%lf",&a[i]);
 76     
 77     int j=0,t=0;
 78     for(int q=2;q<=ptree.count;q++)
 79     {
 80         if(f[q]==0)//最低结点
 81         {
 82             b[t]=1.0;
 83             j=q;
 84             while(j!=1)
 85             {
 86                 b[t]=b[t]*ptree.node[j].data;
 87                 j=ptree.node[j].parents;
 88                 //printf("b[%d]=%lf\n",t,b[t]);
 89             }
 90             t++;
 91         }
 92     }
 93 
 94     //for(i=0;i<t;i++)
 95     //    printf("%lf ",b[i]);
 96     //printf("\n");
 97     //for(i=0;i<n;i++)
 98     //    printf("%lf ",a[i]);
 99     //printf("\n");
100     sort(a,a+n);
101     sort(b,b+t);
102     
103     //for(i=0;i<t;i++)
104     //    printf("%lf ",b[i]);
105     //printf("\n");
106 //    for(i=0;i<n;i++)
107     //    printf("%lf ",a[i]);
108     //printf("\n");
109     for(i=0;i<t;i++)
110     {
111         ans+=(a[i]*b[t-i-1]);
112         
113     }
114     
115     printf("%.10lf\n",ans);
116     return 0;
117 }
View Code

19:33:14

 

不仅仅是一道题的解决,更重要的是背后的知识。加油吧,少年!

                                                                                   by :FZUer

 

 

posted @ 2013-10-29 00:13  陈泽泽  阅读(768)  评论(0编辑  收藏  举报