当前位置:   article > 正文

试题B:01串的熵_图片展示了一段和信息熵相关的内容。具体而言,文本首先给出了一个长度为n的01串s=

图片展示了一段和信息熵相关的内容。具体而言,文本首先给出了一个长度为n的01串s=

一、信息

 1.长度为n的01串S=x1x2x3.....xn

2.香浓信息熵的定义为H(S)=-\sum_{1}^{n}p(xi)\log 2(p(xi))

3.p(0)和p(1)表示在这个01串中0和1出现的占比。

4.比如,S=100来说

1.30803

5.对于一个长度为 23333333 01 串,如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少,那么这个 01 串中 0 出现了多少次?

 二、分析

毫无思路

正确答案:

暴力法:

一、信息

  • 长度为 n=23333333n=23333333 的 01 串。
  • 信息熵 H(s)=11625907.5798H(S)=11625907.5798。
  • 0 的出现次数少于 1。

二、分析

  • 我们需要找到 0 的出现次数,使得熵值为给定的数值。
  • 熵的计算需要使用0和1的概率 p(0) 和 p(1)。
  • 由于熵是一个连续函数,我们可以遍历每一种可能的0的个数来计算熵,并比较它与目标熵。
  • 给定的熵值是一个高精度数值,因此我们需要确定一个误差范围来决定何时接受一个解。

三、算法设计

  • 初始化总长度 n=23333333 和目标熵值。
  • 遍历从 0 到 n 的所有可能的0的个数。
  • 对于每一个可能的0的个数 i,计算 p(0) 和 p(1),然后计算熵。
  • 如果计算出的熵在误差范围内与目标熵相符,则输出当前的0的个数。

四、代码实现(用C++)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int main() {
  4. int n = 23333333;
  5. double target = 11625907.5798;
  6. double tolerance = 0.0001; // 精度范围,可以根据需要调整
  7. for (int i = 0; i <= n; i++) {
  8. double p0 = (double)i / n;
  9. double p1 = 1 - p0;
  10. double entropy = -p0 * i * log2(p0) - p1 * (n - i) * log2(p1);
  11. if (abs(entropy - target) < tolerance) {
  12. cout << i << endl;
  13. break;
  14. }
  15. }
  16. return 0;
  17. }

五、实现代码过程中可能遇到的问题

  • 精度问题:双精度浮点数可能不足以表示非常小的误差,可能需要更高精度的数据类型。
  • 性能问题:暴力遍历可能会非常慢,因为需要检查 �n 个可能的情况。
  • 精度范围的选择:选择一个过大的误差范围可能导致不精确的结果,而过小的误差范围可能导致没有结果。
  • 数学函数的使用:log2函数在某些编译环境下可能需要特别的库或者命名空间。

 

二分法:

一、信息

  • 题目给出了01串的长度n=23333333
  • 给出了01串信息熵的目标值H(S)=11625907.5798
  • 0的出现次数少于1。

二、分析

  • 首先需要理解信息熵的概念,香农信息熵涉及到概率和对数函数。
  • 熵的计算公式是H(S) = −Σp(xi) log2(p(xi)),针对01串,只需要计算0和1出现的概率。
  • 需要找到一个0出现的次数,使得熵值等于目标值。
  • 知道0的出现次数少于1,即0出现的次数的上限是n/2,可设置搜索范围为[0, n/2]。

三、算法设计

  • 使用二分查找来优化搜索过程。初始化low=0high=n
  • 计算中间值mid,利用mid作为0出现的次数来计算熵。
  • 比较计算得到的熵和目标熵,如果接近到一定范围(例如1e-4以内),则认为找到了正确的次数。
  • 如果计算的熵小于目标熵,则需要增加0的次数,即low=mid+1
  • 如果计算的熵大于目标熵,则需要减少0的次数,即high=mid-1
  • 重复上述步骤,直到找到满足条件的0的次数或确定无解。

四、代码实现(用C++)

  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. // 计算熵的函数
  5. double entropy(int zeros, int n) {
  6. if (zeros == 0 || zeros == n) return 0; // 如果0或1的数量为0,熵为0
  7. double p0 = static_cast<double>(zeros) / n;
  8. double p1 = 1.0 - p0;
  9. double entropy = -p0 * log2(p0) * zeros - p1 * log2(p1) * (n - zeros);
  10. return entropy;
  11. }
  12. int main() {
  13. const int n = 23333333;
  14. const double targetEntropy = 11625907.5798;
  15. int low = 0, high = n;
  16. int mid, zeroCount = 0;
  17. double calculatedEntropy;
  18. while (low <= high) {
  19. mid = low + (high - low) / 2;
  20. calculatedEntropy = entropy(mid, n);
  21. if (fabs(calculatedEntropy - targetEntropy) < 1e-4) { // 稍微增加精度范围
  22. zeroCount = mid;
  23. break;
  24. }
  25. if (calculatedEntropy < targetEntropy) {
  26. low = mid + 1;
  27. } else {
  28. high = mid - 1;
  29. }
  30. }
  31. cout << zeroCount << endl;
  32. return 0;
  33. }

五、实现代码过程中可能遇到的问题

  • 精度问题:由于计算熵时涉及浮点数的对数运算,可能会产生精度误差。因此,需要设定一个合理的误差范围来接受结果。
  • 性能问题:对于大规模的数据,二分查找可以大幅减少计算次数。但若精度要求过高,可能需要更多的迭代,因此要平衡精度和性能。
  • 数值稳定性:在计算对数时,如果概率p接近于0或1,可能会导致数值计算上的不稳定。需要确保算法对这种情况有适当的处理。

六、学到了什么?

从这个问题中,我们可以学到以下几点:

  1. 二分搜索算法的重要性:这个问题展示了在处理大数据集时,一个有效算法相比暴力搜索的效率提升。二分搜索显著地减少了必要的计算次数。

  2. 浮点数精度处理:计算过程中必须考虑到浮点数的精度问题。我们必须设定一个实际的精度范围来比较浮点数,因为直接比较可能会因为微小的误差而失败。

  3. 对数学函数的理解:深入理解熵的概念和计算方法以及对数函数的应用是解决这个问题的关键。

  4. 编程技巧:如何在C++中正确使用标准库和函数,以及如何处理特殊情况(比如全为0或全为1时熵为0)。

在处理这个问题时,犯下的错误可能包括:

  1. 初始的误解:一开始,我没有正确理解题目的要求,这表明在解决问题之前,彻底理解问题描述的重要性

  2. 未能立即提供正确解法:我没有立即提供一个有效的解决方案,比如二分搜索,而是尝试了不适合这个问题的方法。

  3. 精度设置不当:在第一次尝试解决问题时,我没有设置一个合适的精度范围,导致没有找到正确的解。

  4. 代码实现问题:在实现代码时,我没有立即考虑到所有可能的边界情况,比如熵为0的情况。

通过这些错误,我们能够学习到在未来的问题解决中,如何更好地分析问题、设计算法和实现代码。每个错误都是一个学习和改进的机会。

从这个问题中,我们可以学习和强调几个关键的思想和方法:

  1. 分治思想

    • 二分搜索是分治算法的一种,这个问题表明了它在处理需要快速定位特定值或条件的大数据集时的强大能力。它将问题划分为更小的部分来解决,而不是一次性尝试解决整个问题。
  2. 算法效率

    • 时间复杂度的概念在算法设计中至关重要。二分搜索的对数时间复杂度(O(log n))与暴力搜索的线性时间复杂度(O(n))相比,效率显著提升。
  3. 浮点数的处理

    • 浮点数的比较不应该直接进行,需要考虑到计算机中浮点数表示的误差。设置一个合理的容差或精度范围是实现这种比较的正确方法。
  4. 边界情况的处理

    • 在算法设计和编程实践中,处理边界情况至关重要。这可以防止运行时错误和逻辑错误,保证程序的健壮性。
  5. 代码的优化

    • 这个问题也教会我们如何通过算法优化来避免不必要的计算,例如,在熵计算中直接返回0而不是进行无用的计算。
  6. 逐步细化

    • 通过逐步细化的过程,我们学会如何将复杂问题简化为更易处理的子问题。这种方法有助于提高问题解决的效率和可行性。
  7. 编程语言工具箱

    • 熟悉并合理利用编程语言提供的工具,如C++中的cmath库,可以帮助我们更快速、更准确地实现算法。
  8. 持续测试和验证

    • 在开发过程中不断测试和验证我们的代码,确保它不仅能在特定例子下工作,而且也能广泛适用于其他情况。

通过这个问题,我们不仅学到了具体的技能和方法,还提醒了我们在进行算法设计和编程时,应该保持的思维方式和注意事项。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/438839
推荐阅读
相关标签
  

闽ICP备14008679号