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

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日

相关文章

  • VScode中C++头文件问题的终极解决方法详析

    下面是详细的攻略: VScode中C++头文件问题的终极解决方法详析 在使用VScode进行C++程序开发时,遇到头文件引用问题是非常常见的。本文将为大家介绍,在VScode中C++头文件问题的终极解决方法,以确保你在开发过程中能够顺畅地引用和编译代码。具体解决方法如下: 第一步:配置includePath 在VScode中,需要配置includePath,…

    C 2023年5月23日
    00
  • C语言指针详解之野指针

    C语言指针详解之野指针 简介 指针是C语言中非常重要的概念,它可以让程序员通过间接访问的方式处理内存中的数据。而野指针是指未被初始化或指向不明确的地址的指针。使用野指针可能会导致内存泄漏、未定义的行为、数据丢失等问题。 本文将详细讲解野指针的概念、产生的原因、如何避免以及实例讲解。 野指针的概念 野指针是未被初始化或指向不明确的地址的指针。它可能指向未被分配…

    C 2023年5月23日
    00
  • C语言volatile关键字的作用与示例

    C语言中的volatile关键字可以用于修饰被多线程访问或外部环境影响的变量,以保证程序访问这些变量的正确性。本文将从定义、作用、使用方法以及实例方面全面介绍volatile关键字的使用。 定义 volatile是C语言的关键字,表示“易变的、多变的、易波动的”,即表示一个全局变量或局部变量,其值可能随时会发生改变,因此每次访问该变量时都必须重新读取变量的值…

    C 2023年5月23日
    00
  • C语言局部数据指针

    当我们在写C语言程序时,经常会定义一些变量,这些变量可以是全局变量,也可以是局部变量。而局部变量是指定义在函数内部或代码块内部的变量,这些变量的作用域仅限于定义它们的函数或代码块内部。那么在定义局部变量时,我们可以定义一个指针变量,它可以指向局部变量的地址。这就是C语言局部数据指针的使用方法。 如下是C语言局部数据指针的使用攻略: 1. 定义局部变量和指针变…

    C 2023年5月9日
    00
  • Swift如何调用Objective-C的可变参数函数详解

    那么首先我们需要了解的是Objective-C中的可变参数函数的使用方式和Swift对其的调用方式。 在Objective-C中,可变参数函数通常使用va_list和va_start、va_arg、va_end等宏来进行参数的处理。其中 va_start宏接受可变参数函数的参数列表以及可变参数的最后一个非变长参数,在获取可变参数时,需要使用 va_arg宏进…

    C 2023年5月23日
    00
  • 移动m812c手机怎么样? 中国移动m812c参数配置详情介绍

    移动M812C手机怎么样? 移动M812C手机是中国移动推出的一款价格亲民的智能手机,旨在提供基本的移动通信和基础应用功能。下面将详细介绍它的参数配置和使用情况。 1. 参数配置 移动M812C手机参数如下: 屏幕:5.45 英寸屏幕,分辨率为 480 x 960 像素 处理器:联发科 MT6739WA 四核处理器 存储空间:2GB RAM + 16GB R…

    C 2023年5月23日
    00
  • SpringBoot参数校验Validator框架详解

    完整攻略:“SpringBoot参数校验Validator框架详解” 一、介绍 SpringBoot是一个非常流行的轻量级Java开发框架,提供了很多便利的功能以及简洁的语法,使得开发者可以更加快速的进行开发。而参数校验也是开发者在开发过程中必须要面对的一项工作,为了保证程序的正确性,一些基本的参数校验是非常必要的。SpringBoot提供了一套非常方便的参…

    C 2023年5月23日
    00
  • Windows 环境下使用 Qt 连接 MySQL

    下面我将为您详细讲解“Windows 环境下使用 Qt 连接 MySQL”的完整攻略。 前置条件 在进行本教程之前,您需要确保您已经做好了以下几项准备: 您已经在 Windows 系统中安装了 Qt; 您已经在 Windows 系统中安装了 MySQL 数据库,并且已经创建了一个数据库。 如果您还没有完成上述准备,请先完成准备工作。 步骤一:安装 MySQL…

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