母函数的定义以及整数拆分模板 母函数(Generating function)详解

分类: 母函数 2012-08-12 20:33 899人阅读 评论(0) 收藏 举报
functionc2010生活

在数学中,某个序列的母函数是一种形式幂级数,其每一项的系数可以提供关于这个序列的信息。使用母函数解决问题的方法称为母函数方法。

母函数可分为很多种,包括普通母函数、指数母函数、L级数、贝尔级数和狄利克雷级数。对每个序列都可以写出以上每个类型的一个母函数。构造母函数的目的一般是为了解决某个特定的问题,因此选用何种母函数视乎序列本身的特性和问题的类型。

由此可以看出:

1. x的系数是a1,a2,…an的单个组合的全体。

2. x2的系数是a1,a2,…a2的两个组合的全体。

………

n. xn的系数是a1,a2,….an的n个组合的全体(只有1个)。

由此得到:

母函数的定义:

对于序列a0,a1,a2,…构造一函数:

称函数G(x)是序列a0,a1,a2,…的母函数

这里先给出2个例子,等会再结合题目分析:

第一种:

有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?每种重量各有几种可能方案?

考虑用母函数来接吻这个问题:

我们假设x表示砝码,x的指数表示砝码的重量,这样:

1个1克的砝码可以用函数1+x表示,

1个2克的砝码可以用函数1+x2表示,

1个3克的砝码可以用函数1+x3表示,

1个4克的砝码可以用函数1+x4表示,

上面这四个式子懂吗?

我们拿1+x2来说,前面已经说过,x表示砝码,x的指数表示重量,即这里就是一个质量为2的砝码,那么前面的1表示什么?1代表重量为2的砝码数量为0个。(理解!)

不知道大家理解没,我们这里结合前面那句话:

"把组合问题的加法法则和幂级数的t的乘幂的相加对应起来"

1+x2表示了两种情况:1表示质量为2的砝码取0个的情况,x2表示质量为2的砝码取1个的情况。

这里说下各项系数的意义:

在x前面的系数a表示相应质量的砝码取a个,而1就表示相应砝码取0个,这里可不能简单的认为相应砝码取0个就该是0*x2(想下为何?结合数学式子)。

Tanky Woo 的程序人生:http://www.wutianqi.com/

所以,前面说的那句话的意义大家可以理解了吧?

几种砝码的组合可以称重的情况,可以用以上几个函数的乘积表示:

(1+x)(1+x2)(1+x3)(1+x4)

=(1+x+x2+x3)(1+x3+x4+x7)

=1+x+x2+2x3+2x4+2x5+2x6+2x7+x8+x9+x10

从上面的函数知道:可称出从1克到10克,系数便是方案数。(!!!经典!!!)

例如右端有2x5 项,即称出5克的方案有2:5=3+2=4+1;同样,6=1+2+3=4+2;10=1+2+3+4。

故称出6克的方案有2,称出10克的方案有1 。

接着上面,接下来是第二种情况:

求用1分、2分、3分的邮票贴出不同数值的方案数:

大家把这种情况和第一种比较有何区别?第一种每种是一个,而这里每种是无限的。

以展开后的x4为例,其系数为4,即4拆分成1、2、3之和的拆分数为4;

即 :4=1+1+1+1=1+1+2=1+3=2+2

这里再引出两个概念整数拆分和拆分数:

所谓整数拆分即把整数分解成若干整数的和(相当于把n个无区别的球放到n个无标志的盒子,盒子允许空,也允许放多于一个球)。

整数拆分成若干整数的和,办法不一,不同拆分法的总数叫做拆分数。

现在以上面的第二种情况每种种类个数无限为例,给出模板:

模板

关于什么是母函数 , 以及在现实生活中的应用 , 请大家详看 或者 HDU 母函数 PPT:

http://www.cppblog.com/MiYu/archive/2010/08/05/122290.html

对于给出的母函数模板 , 让人理解起来比较费劲的!以下给出几种解释 , 和自己理解

//made by syx
//time 2010年9月11日 10:17:27
//母函数例题

/*//整数拆分模板

由于  可以把x^1看成 是重量为1的砝码  对于重量为1的砝码数是无限的 所以就有了式子(1+x^1+x^2+x^3.....)
重量为2的砝码可以组成式子(1+x^2+x^4+x^6+.....)
。。。。。。。
之后各个式子相乘 则x^n前的系数便是方案数 
注意这里的每种砝码数量是无限的   当是有限的时候就要做下限值了 具体看埋葬的其它文章

#include <iostream>
using namespace std;
const int lmax=10000;
//c1是用来存放展开式的系数的,而c2则是用来计算时保存的,
//他是用下标来控制每一项的位置,比如 c2[3] 就是 x^3 的系数。
 //用c1保存,然后在计算时用c2来保存变化的值。
int c1[lmax+1],c2[lmax+1];
int main()
{
            int n, i, j, k ;
           // 计算的方法还是模拟手动运算,一个括号一个括号的计算,
           // 从前往后
            while ( cin>>n )

{
                     //对于 1+x+x^2+x^3+ 他们所有的系数都是 1 
                     // 而 c2全部被初始化为0是因为以后要用到 c2[i] += x ; 
                     for ( i=0; i<=n; i++ )

{
                                c1[i]=1;//蓝色字体表示埋葬个人理解的第一次运行的意义
                                c2[i]=0;//第一次运行 表示出第一个式子的各项系数放进c1
                     }
                      //第一层循环是一共有 n 个小括号,而刚才已经算过一个了
                      //所以是从2 到 n 
                     for (i=2; i<=n; i++)//第一个式子表示完毕 从第二个式子开始乘 一共有n个括号

{
                                 // 第二层循环是把每一个小括号里面的每一项,都要与前一个
                                 //小括号里面的每一项计算。
                                for ( j=0; j<=n; j++ )//j是控制的第一个式子中的每一项(即前一个式子)
                                 //第三层小括号是要控制每一项里面 X 增加的比例 
                                 // 这就是为什么要用 k+= i ; 
                                         for ( k=0; k+j<=n; k+=i )//k是控制第二个式子中的系数(后一个式子)

{                    //而且要保持次数不会超过n 因为最多分解为x的

//n次方即 表示1个质量为n的砝码
                                                 // 合并同类项,他们的系数要加在一起,所以是加法,呵呵。 
                                                 // 刚开始看的时候就卡在这里了。 
                                                 c2[ j+k] += c1[ j];//把乘的的结果即系数的变化放进c2
                                         }
                               // 刷新一下数据,继续下一次计算,就是下一个括号里面的每一项。 
                              for ( j=0; j<=n; j++ )

{
                                          c1[j] = c2[j] ;
                                          c2[j] = 0 ;
                              }
                   }
                    cout<<c1[n]<<endl;
        }
         return 0;
}
这句 c2[j+k] += c1[j];的理解还要自己好好的体会体会啊!
*/

自己理解:对于(#式)  (1+x+x^2+x^3+x^4+x^5+....)*(1+x^2+x^4+x^6+x^8+x^10+....)*(1+x^3+x^6+x^9+x^12....).....

第一个for给c1 和 c2 赋值 , 把上面#式的第一个括号(1+x+x^2+x^3+x^4+x^5+....)的系数给放在c1中,

从而再次计算从 # 的 第二个括号开始 , 所以 i 就是代表的# 式第几个括号,

而 用程序模拟手工计算 , 就是 先计算第一个括号 与 第二个括号 计算 , 把结果放到c2中,

在把结果与第三个括号计算 , 把结果放到c2中 , 在和第四个括号计算,........

所以j 就是指的 已经计算出 的 各项的系数 ,比如第一次之后 1+x+x^2+x^3+x^4+x^5+... , j=0指向1 ,

j=2 指向x , .... , 而 k 就是指 将要计算的那个括号中的项 , 因为第i个括号 , 中的指数为0 , i , 2i....所以 k要 + i ;

而结果 c2[j+k] += c1[j]; 就是把 以计算出的 j项的系数 和 现在正在计算的括号的k项相乘 , 所以指数为j+k , 所以结果放到c2[j+k] 中 , 这就是这几个for的作用!

最后刷新下结果 , 下一组数据计算!

埋葬个人的理解

对于(#式)  (1+x+x^2+x^3+x^4+x^5+....)*(1+x^2+x^4+x^6+x^8+x^10+....)*(1+x^3+x^6+x^9+x^12....).....

1第一个for给c1 和 c2 赋值 , 把上面#式的第一个括号(1+x+x^2+x^3+x^4+x^5+....)的系数给放在c1中,

从而再次计算从 # 的 第二个括号开始 ,

所以 i 就是代表的# 式第几个括号

2 j即第i个式子中的第j项

3而 k 就是指 将要计算的那个括号中的项 , 因为第i个括号x中的指数为0 , i , 2i....所以 k要 + i ;

4  c2[ j+k] += c1[ j];

c2[j] c1 [j]是指 即次数为j的系数;

c1是用来存放展开式的系数的 而c2则是用来计算时保存的

这里指c1[j]乘以k之后 次数也变成了j+k, 故c2[j+k]的系数要增加c1[j]个;

5 n是砝码的个数

新例题:hdu1085 用1 2 5的硬币买不到的东西的价值(输出最小的)3者数量分别为num1 num2 num3

#include "stdio.h"

int c1[10000],c2[10000];

int main()

{

int i,j,k,num1,num2,num3,n;

while(scanf("%d %d %d",&num1,&num2,&num3)!=EOF)

{

if(!num1&&!num2&&!num3) break;

n=num3*5+num2*2+num1;

for(i=0;i<=n;i++)

{

c1[i]=0;

c2[i]=0;

}

for (i=0;i<=num1;i++)

c1[i]=1;

for(j=0;j<=num1;j++)

//    for (k=0;k+j<=num2*2;k=k+2)//num2*2表示最多可能达到的次数

for (k=0;k<=num2*2;k=k+2)//num2*2表示最多可能达到的次数

{  //注意  这里不要用k+j<=num2 因为以前求整数拆分输入数n 要保证次数小于n 因为最大为

//x的n次方 表示为1个重为n的砝码     这里是求多项式相乘 不用限制了

c2[j+k]+=c1[j];

}

for (j=0;j<=num2*2+num1;j++)//因为 下面的c2[j] 中的下标最大为j+k 由上一步可以看出 而j最大为num1 k最大为num2*2

{

c1[j]=c2[j];

c2[j]=0;

}

for(j=0;j<=num2*2+num1;j++)//num1和num2*2不一定那个大那 要表示出所有的项数 所以要这样

for(k=0;k<=num3*5;k+=5)

c2[j+k]+=c1[j];

for (j=0;j<=num3*5+num2*2+num1;j++)

{

c1[j]=c2[j];

c2[j]=0;

}

for (i=0;i<=n;i++)

if(!c1[i])  {printf("%d\n",i);break;}

if(i==n+1) printf("%d\n",i);

}

}

说白了就是求多项式的值

母函数理解及整数拆分相关推荐

  1. 母函数——整数拆分(HDOJ2152)

    最近看到了一些关于母函数的题目,去网上找了一些材料,加上自己的理解,现在可以解决一些简单的问题.那么什么是母函数?其实这个问题我也没有怎么搞懂,通过几个例子来说明一下.下面是转载的一个介绍 http: ...

  2. 整数拆分的两种解法(已完成)

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 整数拆分 ...

  3. 整数拆分 python_LeetCode 343. 整数拆分 | Python

    343. 整数拆分 题目 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. 示例 1: 输入: 2 输出: 1 解释: 2 = 1 + 1, 1 ...

  4. 数学上的整数拆分问题

    整数拆分是一个经典的数学问题,我们从小学奥数,一直到大学的组合数学,可能都会遇到.从字面意思来看,是将一个整数拆分成若干整数之和,求的是不同的方案个数.我今天想讨论的问题是 " 无序拆分 & ...

  5. 整数拆分问题的四种解法

    整数划分问题是算法中的一个经典命题之一 所谓整数划分,是指把一个正整数n写成如下形式: n=m1+m2+m3+....+mi;(其中mi为正整数,并且1<=mi<=n),则{m1,m2,m ...

  6. 知识点 - 分拆数/整数拆分

    知识点 - 分拆数/整数拆分 解决问题类型: 将一个数用一个或多个正整数的无序和来表示有几种方案. 这是一个母函数的应用,利用了母函数的指数系数是五边形数来优化复杂度. 结论 (1)称正整数n分解为r ...

  7. 动态规划 - 整数拆分

    对于动态规划的思路,在这就不多说了,需要理解的看下这一篇文章动态规划步骤​​​​​​, 下面直接进入主题,利用动态规划思路来解决343. 整数拆分 - 力扣(LeetCode). 第一步.确定数组dp ...

  8. python 整数 拆分 分段

    整数 拆分 分段 不平均分 int1 = 68 # 整数 sub = 3 # 要分成几段 interval = int1 // sub rem = int1 % sub print("余数: ...

  9. LeetCode-动态规划基础题-343. 整数拆分

    描述 343. 整数拆分 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. 示例 1: 输入: 2 输出: 1 解释: 2 = 1 + 1, 1 ...

  10. python分割数字_python实现整数拆分,输出拆分序列

    昨天笔试VIPKID有一道关于整数拆分的题目,要求输出拆分后的序列,当时没有做出来,记录一下可以实现的想法: 题目示例: 从键盘读入一个数 n, 输出所有和为 n 的子序列和,包括 n 测试用例: 输 ...

最新文章

  1. php 接收curl json数据格式,curl发送 JSON格式POST数据的接收,以及在yii2框架中的实现原理【精细剖析】...
  2. iPhone 的 Push(推送通知)功能原理浅析
  3. 先河系统为你讲解私有云服务器的优点
  4. 单摆运动属于什么现象_物理模型中的隐含条件是什么
  5. 百度ERNIE新突破!登顶中文医疗信息处理权威榜单CBLUE冠军
  6. 44.mysqlbinlog
  7. 银监会再出新规!银行数据治理与监管评级挂钩
  8. Delphi2010Excel导入数据库
  9. 如何修改Maven本地仓库位置
  10. QT+SQL Server实现车辆管理系统 -代码具体实现
  11. SIM868模块+Arduino将位置信息上传到服务器
  12. Java计算两点间的距离
  13. 解除开启全局 UWP应用网络隔离限制
  14. 三角学(一)公式,恒等式,函数和难题
  15. 买房贷款月供怎么算?贷款利息是多少?
  16. 理想中2.5D的网络拓扑图
  17. Cookie加密10
  18. 苏州博物馆计算机系统操作工,行车及铁钢包调度系统在炼钢厂应用.doc
  19. CTC Loss (一)
  20. 编程序也得劳逸结合,不能太累。。。

热门文章

  1. php a标签加nofollow,Z-Blog给文章所有的站外a链接添加nofollow的方法
  2. 德州仪器发布99%高效GaN逆变器功率级的参考设计
  3. 网站获取微信授权登录功能
  4. storage ( initial 64K minextents 1 maxextents unlimited );
  5. html打砖块游戏制作,JavaScript实现打砖块游戏
  6. 程序人生 - 创可贴使用不当或致截肢
  7. “约定优于配置”与Magento总结
  8. css 页面设计,60个精品CSS网页设计欣赏
  9. php天籁吉他乐器介绍网站系统
  10. 规则库捕获漏洞信息专用脚本