猜球球

题面:

有n个盒子,有个小球小球出现在每个盒子的概率为p[i],你现在可以问类似(小球是否在盒子{1,4,……,n}中?)(1-n的一个子集)的问题,问策略最优情况下,猜出小球所在盒子的猜测次数的数学期望。

思路:

因为任意一次询问和回答,都可以确定其中一半的球球集合包含目标球,另一半则不包含目标球。然后再对包含目标球的球球集合进一步划分,直到包含目标球的集合里只包含一个球,就可以百分百确定了。这样就得到了一个决策树(二叉形状),二叉决策树根节点到每个叶子的路到都是期中一种情况的解决方案,显然深度就是询问次数。 则有:

期望=∑(询问次数每种情况出现的概率)

=∑(叶子对应的深度它出现在盒子里的概率)。

而我们知道:这个公式 ∑(深度*元素出现的概率 ) 与某种编码方案的编码长度期望公式 相同。询问次数的期望最小也就是编码长度的期望最小。而解决这个问题的经典方法就是——哈夫曼树。

一句话总结:构造一棵哈夫曼树,然后有

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef pair<double,int>pa;
 4 const int N=20000;
 5  
 6 vector<int> G[N];
 7 double a[N],ans;
 8 int n,cnt;
 9 priority_queue<pa,vector<pa>,greater<pa> >q;
10  
11 void dfs(int x, int d) {
12     if (G[x].size() == 0) ans += a[x] * d;
13     for (auto it : G[x]) {
14         dfs(it, d + 1);
15     }
16 }
17 int main() {
18     scanf("%d",&n);
19     for (int i=1;i<=n;i++) {
20         scanf("%lf", &a[i]);
21         if (a[i] == 0) {
22             n--;
23             i--;
24             continue;
25         }
26         q.push(pa(a[i], i));
27     }
28     cnt=n;
29     while (q.size() >= 2) {
30         pa t1 = q.top();
31         q.pop();
32         pa t2 = q.top();
33         q.pop();
34         pa t3(t1.first + t2.first, ++cnt);
35         q.push(t3);
36         G[cnt].push_back(t1.second);
37         G[cnt].push_back(t2.second);
38     }
39     dfs(q.top().second, 0);
40     printf("%.7lf
", ans);
41 }
View Code
原文地址:https://www.cnblogs.com/Accpted/p/11185521.html