C语言:巧用杨辉三角求二项展开式的系数

巧用杨辉三角求二项展开式的系数

标签: C语言 杨辉三角 二项式展开式

by 小威威

1.引入

我们知道,求二项式展开式系数可根据牛顿的二项式定理,即利用组合数求系数。其实,二项式展开式系数其实也是满足杨辉三角的。

在高中的时候,我们一般用组合数求二项式展开式系数,但是对于编程,这一方法就显得十分勉强。因为当n较大时,n的阶乘非常大,很难有数据类型能够存储。虽然用杨辉三角的方法也会出现类似情况,但是杨辉三角有挽回的余地,阶乘根本没有挽回的余地。

2.实例

例题如下:

给出一个多项式(x+y)^K,询问x^n * y^m的系数

输入两个数n, m。 K为n+m的和。n,m均不超过100

因为系数可能非常大,所以要求输出模10007后的结果

样例输入

1 2

样例输出

3

这道题本质上就是求二项式展开式的某个系数。起初我的第一反应就是通过求组合数来求解系数,我用递归构造了一个阶乘,发现超时了;我就把递归改成for循环,虽然不超时了,但当n较大时,结果不正确,说明数据超过数据类型所能承受的范围之外了。

所以,我也很无奈地改变方法,用杨辉三角。

首先是构造杨辉三角,杨辉三角的行数是m+n+1(自己在草稿纸上画出杨辉三角并将其与二项式展开式对应便可发现规律)。

然后就是输出杨辉三角中对应位置的数值。嗯,就这么简单。现在放代码:

# include <stdio.h>
# include <stdlib.h>
# include <math.h>
int main(void) {
    int m, n, k;
    long long **pArr;
    scanf("%d%d", &n, &m);
    k = m + n;
    pArr = malloc(sizeof(*pArr)*(k+1));
    for (int i = 0; i < k+1; i++) {
        pArr[i] = malloc(sizeof(**pArr)*(k+1));
    }
    for (int i = 0; i < k+1; i++)
        pArr[i][0] = 1;
    int end = 1;
    for (int i = 1; i < k+1; i++) {
        pArr[i][end] = 1;
        end++;
    }
    for (int i = 2; i < k+1; i++)
        for (int j = 1; j < i; j++) {
            pArr[i][j] = (pArr[i-1][j-1] + pArr[i-1][j]) % 10007;
    }
    long long result;
    if (m == k || n == k) {
        printf("1\n");
        return 0;
    } else {
        result = pArr[k][m];
    }
    printf("%lld\n", result);
    for (int i = 0; i < k+1; i++)
        free(pArr[i]);
    free(pArr);
    return 0;
}

此题难点在于这一段。我主要讲解这一段。

for (int i = 2; i < k+1; i++)
        for (int j = 1; j < i; j++) { pArr[i][j] = (pArr[i-1][j-1] + pArr[i-1][j]) % 10007; }

杨辉三角内的数值随着行数的增加而快速地增加,一定会在某一行超过我们所定义的数据类型,这样一来当数值一大时,无论你对结果怎么操作,最终结果都是错的。如你对结果取余,结果本来就是错的,你取余又有什么用。而我们要知道,对两个数的和取余等价于分别对这两个数取余之和,这点是非常重要的,因为在我们现在这种情况下,你先取余在相加与加完再取余是有区别的。你分别取余后相加,数值也许不会超出数据类型所能承受的范围,但是你先将两个数相加,然后再取余,这时,当你这两个数相加以后得到的数可能已经超出了数据类型所能承受的范围,此时数据已经溢出,你再取余结果都是错的。因为杨辉三角行与行之间的关系主要是通过加法建立起来的,既然我们要对结果取余,那倒不如对杨辉三角内每个元素取余后再相加得到下一行的元素,这样做对防止数据的溢出起到了很大的作用。

3.总结

以后对于这一类问题,当数据的范围较小时,我们可以考虑组合数的方法,但是当数据范围较大时,我们一定要使用杨辉三角。但是在编程中,很少会用组合数求解题目,因此要尽量避免。

以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!

    原文作者:小威威__
    原文地址: https://blog.csdn.net/linwh8/article/details/50472506
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞