用母函数的思路解释母函数的代码

本文介绍了一种使用母函数解决硬币组合问题的方法,通过构造特定的母函数并分解多项式,来计算给定金额下硬币的不同组合数量。文章提供了详细的编程思路和示例代码。

原文链接:http://www.cnblogs.com/lijunle/archive/2010/09/04/1817764.html

转载其中一部分

该文章建立在你已经看过母函数的相关数学知识的基础上,如果没有看过,建议看一下 hdu 论坛的母函数课件,传送门:http://acm.hdu.edu.cn/forum/read.php?tid=3853

用一个最简单的例子说明代码:

硬币面值有1元、5元、10元、25元、50元,一共5种,对于一个钱数 money,可以有多少中兑现方法?

很容易地构造母函数

G(x) = (x^0 + x^1 + x^2 + …) * (x^0 + x^5 + x^10 + …) * (x^0 + x^10 + x^20 + …)

       * (x^0 + x^25 + x^50 + x^75 + …) * (x^0 + x^50 + x^100 + x^150 + …)

数学上的思路就拆开这个多项式因式,看看 x^money 的系数是多少。所以,编程的关键是如何实现拆分?

思路是 先把前面两个因式拆开,得到一个因式,代替第二个因式;然后用第二个因式(求出来的因式)和第三个因式相乘,代替第三个因式;递归计算到最后一个因式,得出结果。

由于便于编程的实现,我们在 G(x) 前面加多一个因式 (1*x^0 + 0*x^1 + 0*x^2 + … ),这个因式为1,所以并不改变母函数的值。把已经计算出来的因式的系数存放到一个数组 a 里面,把当前因式与下一个因式乘起来的因式的系数放到另外一个数组 b 里面。两个因式乘完了,就把 b 数组里面的数据放到 a 数组里面,把 b 数组清空,重复刚才的步骤,直到最后一个因式都乘进去了,才结束。此时,a 数据里面存放的就是拆分开来的多项式的系数。

代码如下:

#define M 500
 
int a[M];
int b[M];
 
void GenerationFunction()
{
    int cent[5] = {1, 5, 10, 25, 50};
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    a[0] = 1; // 手动添加的一个多项式因式 (1*x^0 + 0*x^1 + 0*x^2 + … )
    for(int i = 0; i < 5; i ++) // i 指向第几个多项式因式(从0开始算)
    {
        for(int j = 0; j < M; j ++)
        {   // j 指向已经算出来的因式的指数,a[j] 存放的是指数为 j 的项的系数
            for(int k = 0; j+k < M; k += cent[i])
            {   // k 代表下一个因式的指数,因式的指数是隔 cent[i] 递增的。
                // 另外,因式中,指数为 k 的项的系数为 1
                 
                b[j+k] += a[j]; // 对于 a[j] * x^j * x^k = a[j] * x^(j+k) 
                                // 就把 x^(j+k) 的系数 a[j] 加到 存放当前答案的数组 b 里面
            }
        }
        for(int j = 0; j < M; j ++)
        { // 把数组 b 元素滚动到 数组 a 去,以便递归进行乘法运算;另外,清空数组 b
            a[j] = b[j];
            b[j] = 0;
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值