转自:大数量级组合数的快速计算方法,保存在此以学习。

计算组合数最大的困难在于数据的溢出,对于大于150的整数n求阶乘很容易超出double类型的范围,那么当C(n,m)中的n=200时,直接用组合公式计算基本就无望了。另外一个难点就是效率。

对于第一个数据溢出的问题,可以这样解决。因为组合数公式为:

C(n,m) = n!/(m!(n-m)!)

为了避免直接计算n的阶乘,对公式两边取对数,于是得到:

ln(C(n,m)) = ln(n!)-ln(m!)-ln((n-m)!)

进一步化简得到:

这样我们就把连乘转换为了连加,因为ln(n)总是很小的,所以上式很难出现数据溢出。

为了解决第二个效率的问题,我们对上式再做一步化简。上式已经把连乘法变成了求和的线性运算,也就是说,上式已经极大地简化了计算的复杂度,但是还可以进一步优化。从上式中,我们很容易看出右边的3项必然存在重复的部分。现在我们把右边第一项拆成两部分:

这样,上式右边第一项就可以被抵消掉,于是得到:

上式直接减少了2m次对数计算及求和运算。但是这个公式还可以优化。对于上面公式里的求和,当m<n/2时,n-m是一个很大的数,但是当m>n/2时,n-m就会小很多。我们知道:

C(n,m) = C(n,n-m)

那么通过这个公式,我们可以把小于n/2的m变为大于n/2的n-m再进行计算,结果是一样的,但是却能减少计算量。

当计算出ln(C(n,m))后,只需要取自然对数,就可以得到组合数:

C(n,m) = exp(ln(C(n,m)))

这样就完成了组合数的计算。

用这种方法计算组合数,如果只计算ln(C(n,m))的话,n可以取到整型数据的极限值65535,

ln(C(65535,32767)) = 45419.6

而计算时间只需要0.01ms。当然,如果要取对数得到最终的组合数的话,n的取值就不能达到这么大了。但是这种算法仍然可以保证n取到1000以上,而不是开头说的150这个极限值。例如:

C(1000,500) = 2.70288e+299

计算时间仍然小于0.01ms。

采用我这种算法,不仅n的取值范围大,而且计算速度高,不像用递归算法实现这个问题的时候,很容易陷入递归层次太深而导致计算时间太长。

算法代码实现如下:

double lnchoose(int n, int m)
{

if (m > n)

{

return 0;

}
    if (m < n/2.0)
    {
        m = n-m;
    }

double s1 = 0;
    for (int i=m+1; i<=n; i++)
    {
        s1 += log((double)i);
    }

double s2 = 0;
    int ub = n-m;
    for (int i=2; i<=ub; i++)
    {
        s2 += log((double)i);
    }

return s1-s2;
}

double choose(int n, int m)
{

if (m > n)

{

return 0;

}
    return exp(lnchoose(n, m));
}

大数量级组合数的快速计算方法相关推荐

  1. 【JY】钢筋混凝土正截面极限承载力设计的基本原理和快速计算方法

    本文转自 筑信达-李楚舒教授高工 的文章,关于快速计算PMM相关面的新方法,对于混凝土分析有较深刻的理解,文章内容充实丰富,与各位读者分享! [摘要] 本文从钢筋混凝土正截面极限承载力设计的基本原理出 ...

  2. 阶乘数的快速计算方法

    阶乘数的快速计算方法 如何快速计算阶乘数n!?一种简单的办法是采用下面的循环: fac=1; for (k=2;k<=n;k++) fac*= k; 最后的fac值即为n!的值.当然,当n较大, ...

  3. 组合数的常见计算方法

    组合数的常见计算方法 低级版 方法概述 程序实现 时间复杂度 高级版 方法概述 Lucas定理 exLucas定理 其他 低级版 方法概述 直接用组合数性质中的③式递推即可 程序实现 int mod, ...

  4. 计算机基础—任意整数补码的快速计算方法

    这几天读<深入理解计算机系统>(英文名: Computer Systems : A Programmer's Perspective)一书时,再次复习到了整数的各种类型及其表示方法.本科学 ...

  5. 计算机函数乘法word,乘法快速计算方法Word版

    <乘法快速计算方法Word版>由会员分享,可在线阅读,更多相关<乘法快速计算方法Word版(10页珍藏版)>请在人人文库网上搜索. 1.传播优秀Word版文档 ,希望对您有帮助 ...

  6. 计算机机房ups电池常用配置表,机房UPS电池容量、后备电池配置、使用时间快速计算方法!...

    原标题:机房UPS电池容量.后备电池配置.使用时间快速计算方法! UPS-Uninterruptible Power System是不间断电源系统的简称,作用是提供不间断的稳定电中断(停电)时UPS之 ...

  7. 离散傅里叶变换 - 快速计算方法及C实现 - 第一篇

    DFT – Fast algorithms and C implementations - Part1 引言 算法中经常用到傅里叶变换,很长一段时间我都是使用FFTW("the fastes ...

  8. 算法刷题-数论-组合数、快速幂、逆元、递推求组合数、逆元求组合数

    文章目录 acwing885. 求组合数 I(递推:数据范围:2000) acwing875. 快速幂(a的k次方 模 b) acwing876. 快速幂求逆元 acwing886. 求组合数 II( ...

  9. [CSP-S模拟测试]:涂色游戏(DP+组合数+矩阵快速幂)

    题目描述 小$A$和小$B$在做游戏. 他们找到了一个$n$行$m$列呈网格状的画板.小$A$拿出了$p$支不同颜色的画笔,开始在上面涂色.看到小$A$涂好的画板,小$B$觉得颜色太单调了,于是把画板 ...

最新文章

  1. py 的 第 31 天
  2. ggplot01:R语言坐标轴离散、连续与图例离散连续的区分
  3. spring AOP编程
  4. Python subprocess
  5. Linux的逻辑卷状态不可用,linux – 逻辑卷在引导时处于非活动状态
  6. SQL Server 2022 DataSheet
  7. 解压 .solitairetheme8 文件
  8. vivado 开发教程(二) 使用IP集成器
  9. 汽车故障诊断技术【12】
  10. cocosCreator 全局变量(Ts版)
  11. mysql数据库的用户是什么_mysql 数据库用户管理
  12. 二、lintcode刷题记录--二叉树的路径和
  13. 最新注册谷歌账号遇到此号码无法验证的解决办法_看我如何成功注册gmail
  14. 分享一个react 图片上传组件 支持OSS 七牛云
  15. 摩斯密码php,普及一下LOL中的摩斯密码 绝对的干货
  16. 说说抖音和小红书的交互和界面设计,您更喜欢哪一个?
  17. 关于处理公司内网办公系统登录不了的问题
  18. 第三方支付平台BeeCloud
  19. 我和 TiDB 的故事 | 缘份在,那就终是能相遇的
  20. 计算机网络第一弹——基础概念

热门文章

  1. TensorFlow 决策森林来啦!
  2. 关于多对多关系(即E-R图中m:n)中的界面展示优化
  3. VMware Workstation 不可恢复错误: (vmx)Exception 0xc0000006 (disk error while paging) has occurred.
  4. echarts 图表不能占满全屏
  5. 如何用idea比对代码差异
  6. mysql slave 'system user' locked_Mysql的slave lags一例
  7. IPhone多视图切换
  8. React通过后台图片路径,打包下载图片
  9. uni-app获取元素节点信息
  10. 使用uncompyle2直接反编译python字节码文件pyo/pyc