C++中求组合数的各种方法总结详解

yizhihongxing

C++中求组合数的各种方法总结详解

前言

组合数问题在许多算法问题中都有广泛应用,在C++中求组合数的方法也多种多样。本文将总结并详细解释C++中求组合数的各种方法。

直接递推法

组合数的定义式为:$C_{n}^{m}=\frac{n!}{m!(n-m)!}$,可以通过递归的方法直接求解。

递归式为:$C_{n}^{m}=C_{n-1}^{m-1}+C_{n-1}^{m}$

具体实现代码如下:

int C(int n, int m)
{
    if (m == 0 || n == m)
        return 1;
    else
        return C(n - 1, m - 1) + C(n - 1, m);
}

该方法简单易懂,但运行时间可能比较长,特别是当n和m较大时,时间复杂度为O($2^n$)。

非递归的递推法

通过分析递推公式,我们可以发现$C_{n}^{m}$只与$C_{n-1}^{i}(i\leq m)$有关。

所以可以通过非递归的方法提高运算速度。

具体实现代码如下:

const int MAXN = 1005;
const int MOD = 1e9 + 7;

int C[MAXN][MAXN];

void init()
{
    for (int i = 0; i < MAXN; i++)
    {
        C[i][0] = 1;
        for (int j = 1; j <= i; j++)
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
    }
}

int main()
{
    init();
    cout << C[10][5] << endl; //输出组合数C10,5
    return 0;
}

该方法通过预先计算组合数,可以大大减少递推计算量,运行时间为$O(n^2)$。

Lucas定理

Lucas定理是一种用于解决组合数取模问题的算法。它是利用了组合数的整除性质来实现的。

Lucas定理为:$C_{m}^{n}\ \mbox{mod}\ p=C_{m\ \mbox{mod}\ p}^{n\ \mbox{mod}\ p}\cdot C_{(\lfloor\frac{m}{p}\rfloor) }^{(\lfloor\frac{n}{p}\rfloor) }$

具体实现代码如下:

const int MAXN = 1005;
const int MOD = 1e9 + 7;

int C(int n, int m, int p)
{
    if (m == 0 || n == m) return 1;
    int a[MAXN], b[MAXN];
    for (int i = 1; i <= p; i++)
        if (i % p) a[i] = a[i - 1] * i % p;
    b[p - 1] = ksm(a[p - 1], p - 2, p);
    for (int i = p - 2; i >= 1; i--)
        if ((i + 1) % p) b[i] = b[i + 1] * (i + 1) % p;
    int res = 1;
    while (n && m)
    {
        int n1 = n % p, m1 = m % p;
        if (n1 < m1) return 0;
        res *= a[n1] * b[m1] % p * b[n1 - m1] % p;
        res %= p;
        n /= p, m /= p;
    }
    return res;
}

int main()
{
    cout << C(10, 5, MOD) << endl; //输出组合数C10,5
    return 0;
}

该方法在求解组合数时,会先将n、m、p转化为p进制,然后分别计算每一位上对应组合数的值,最后通过有限域上的计算方法(同余性质)得到答案。时间复杂度为$O(p\log _p n)$,具体计算时间随p的取值有关。

特别提示

特别提示:在进行组合数计算时,如果数据范围较大,一定要取模防止溢出。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++中求组合数的各种方法总结详解 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • 如何查看Win10笔记本电池状况及电量详细报告?

    下面是详细讲解如何查看Win10笔记本电池状况及电量详细报告的攻略: 1. 查看电池状况 Windows 10提供了自带的电池健康报告工具,使用方法如下: 1.1. 打开”Windows PowerShell”命令行工具 可以通过在任务栏搜索栏中输入”PowerShell”,并点击”Windows PowerShell”应用程序来打开该命令行工具。 1.2.…

    C 2023年5月23日
    00
  • C语言实现酒店管理系统

    C语言实现酒店管理系统攻略 简介 C语言可以用于实现各种系统,例如酒店管理系统。在这个过程中,我们需要用到C语言的基本操作、条件语句、循环语句、函数、指针等知识点。 需求分析 在开始编写代码之前,我们需要先进行需求分析,明确我们要实现的功能。在酒店管理系统中,我们通常需要实现以下功能: 客房信息管理(包括添加客房、删除客房、修改客房信息、查询客房信息) 客户…

    C 2023年5月22日
    00
  • C语言实现火车订票系统

    实现火车订票系统的完整攻略分为以下几个步骤: 1. 设计数据库 火车订票系统需要一个数据库来存储车次信息、座位信息、乘客信息等。可以使用MySQL或者SQLite等关系型数据库。设计数据库时需要考虑信息的表结构、字段类型、约束条件等。以下是一个汽车票订购系统的数据库设计: 车次信息表:train_info 字段:train_id, start_station…

    C 2023年5月22日
    00
  • 荣耀畅玩8c怎么截长图?荣耀畅玩8c滚动截屏方法

    荣耀畅玩8c是一款性价比比较高的手机,它内置了截屏功能来满足用户的需求,但是有时我们需要截取长图或进行滚动截屏,下面将详细讲解“荣耀畅玩8c怎么截长图?荣耀畅玩8c滚动截屏方法”的完整攻略。 荣耀畅玩8c截取长图方法 荣耀畅玩8c提供了系统自带的截屏功能,但是它只能截取屏幕内的内容,对于需要截取较长的页面就不太适用了。下面介绍一种轻松截取长图的方法。 打开需…

    C 2023年5月23日
    00
  • c++中.dll与.lib文件的生成与使用的详解

    C++中.dll与.lib文件的生成与使用的详解 在Windows系统下,动态链接库(DLL)和静态库(LIB)是常用的代码重用手段。在C++中,我们可以通过Visual Studio来生成这两种库文件。 一、生成DLL文件 DLL(Dynamic-link Library)可以在程序运行时动态加载,它可以实现代码共享和隔离。下面是生成DLL文件的步骤: 在…

    C 2023年5月23日
    00
  • Golang json 库中的RawMessage功能原理

    完整攻略:Golang json 库中的 RawMessage 功能原理 1. RawMessage是什么 在Golang中,RawMessage 是一个预定义类型,它用于存储任意未经处理的 JSON 数据。 它允许我们将复杂的任意 JSON 对象作为struct中的一部分而不必定义对应的struct。 2. RawMessage的使用方法 2.1 Unma…

    C 2023年5月23日
    00
  • 详解C/C++如何获取路径下所有文件及其子目录的文件名

    获取一个文件夹下的所有文件及其子目录的文件名可以通过递归遍历文件夹来完成。以下是几个示例代码,演示如何实现这个功能。 方法一:使用C++17中的std::filesystem 基于C++17标准,可以使用std::filesystem库来遍历目录。下面是示例代码: #include <iostream> #include <filesyst…

    C 2023年5月23日
    00
  • JavaScript实现JSON合并操作示例【递归深度合并】

    JavaScript实现JSON合并操作示例【递归深度合并】 在JavaScript开发中,我们经常需要合并两个或多个JSON对象。如果不加注意,使用原生JavaScript合并JSON对象会遇到一些问题,比如仅会执行浅合并(只合并顶级属性且不支持数组合并)、忽略null和undefined属性。下面我们来介绍递归深度合并两个JSON对象的方法,解决上述问题…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部