母函数 基础
来源:互联网 发布:美国8月非农数据 编辑:程序博客网 时间:2024/04/29 17:17
今天看了下母函数,纠结了好长时间,终于在和队友的讨论下自我感觉弄懂了。。。
母函数多用于处理排列组合问题,我们还是拿常见的举例子吧:
假如现在有面值为 2 3 5 的三种硬币各一枚,问能组成多少种不同的面值?每种面值的组合方式有多少种?
首先,我们用X表示硬币,X的指数表示硬币能表示的面值。那么,如果用函数表示每个硬币可以组成的面值,那么
面值为2的硬币可以表示的函数为 x^0+x^2;
面值为3的硬币可以表示的函数为 x^0+x^3;
面值为5的硬币可以表示的函数为 x^0+x^5;
即如果该硬币参与组成面值,那它能表示的面值为2,3,5,如果不参与,就相当于组成的面值为0;
把上面的多项式乘起来,我们会发现一点小规律:
(x^0+x^2)*(x^0+x^3)=x^0+x^2+x^3+x^5;
(x^0+x^2+x^3+x^5)*(x^0+x^5)=x^0+x^2+x^3+2*(x^5)+x^7+x^8+x^10;
我们发现:
2 3 5能组成面值为0的种数为1,即都不选
2 3 5能组成面值为2的种数为1,即选2
2 3 5能组成面值为3的种数为1,即选3
2 3 5能组成面值为5的种数为2,即选5或(2,3)
2 3 5能组成面值为7的种数为1,即选(2,5)
2 3 5能组成面值为8的种数为1,即选(3,5)
2 3 5能组成面值为10的种数为1,即选(2,3,5)
二项式的项数就是能组成的面值的种数,二项式 每项前面的系数就是 组成该项二项式指数的种数(二项式的指数表示能组成的面值)
上面介绍的是给定你每个面值的数量为1,现在假如三种面值的数量依次为3 7 4,那能每项能构成的函数是什么呢?
面值为2的硬币可以表示的函数为 x^0+x^2+x^4+x^6;
面值为3的硬币可以表示的函数为 x^0+x^3+x^6+x^9+x^12+x^15+x^18+x^21;
面值为5的硬币可以表示的函数为 x^0+x^5+x^10+x^15+x^20;
我们又会从上式中发现这样一个规律:
对于第i个二项式的第k项的指数,它是这样构成的:即由第i个数的权值(即硬币面值)*k(k为当前面值的硬币的个数,k的范围为0-k);
上面介绍的是每种硬币的数量为定值,如果每种硬币的数量为无穷多个,那该如何表示?
面值为2的硬币可以表示的函数为 x^0+x^2+x^4+x^6+...;
面值为3的硬币可以表示的函数为 x^0+x^3+x^6+x^9+...;
面值为5的硬币可以表示的函数为 x^0+x^5+x^10+x^15+...;
通过上面的构造函数,也可以发现大概也只有这三种问题:
1,给你多种东西,每种只有一个,求构造一个X的组合数
2,给你多种东西,每种有mi个,求构造一个X的组合数
3,给你多种东西,每种无穷多,求构造一个X的组合数
通过上面的三个问题,我们又会发现,只要构造出来的二项式的指数小于等于X,那么它就是一个合理的构造,现在的问题就转化为用函数构造二项式;
说完上面的普通母函数,也说一下指数型母函数:
其实这个不算是一个问题,因为有模板
模板之一如下:
memset(c1,0,sizeof(c1));c1[0]=1; //初始化for(int i=1; i<=m; i++) //循环每个因子,一般来说种类数(因子数)都会给出来{ memset(c2,0,sizeof(c2)); for(int j=0; j*v[i]<=n; j++)//每个因子的每一项---->1 { for(int k=0; k+j*v[i]<=n; k++)//循环c1数组的每一项----->2 c2[k+j*v[i]] += c1[k]; } memcpy(c1,c2,sizeof(c2));}printf("%d\n",c1[n]);
这里详细说一下1,2位置的不同处理方法:
对于位置1,循环的是每个因子的每一项,一般情况下每个因子的权值是已知的,需要组合出的数也是已知的,如果每个因子的个数num【i】都知道,则限制条件就是
j<=num[i]&&j*v[i]<=n;如果每个因子的个数无穷多,则j<=num[i]可省略;
对于位置2,循环的事c1数组里的每一项,故k从0开始循环,并且要保证k+j*v【i】小于等于要组合出的数n
对于模板之二,其实就是和模板一差不多,不过模板二对每次循环的边界加了控制,避免的不必要的循环;
模板之二如下:
//假设v[i]为第i个物品的价值,num[i]为第i个物品的数量memset(c1,0,sizeof(c1));c1[0]=1;int max=0,max1;//max为当前c1数组里最大的指数,即最大能组合出的数for(int i=1; i<=n; i++)//循环每个因子{ max1=max+v[i]*num[i];//每次循环的界限控制的恰到好处 for(int j=0; j<=num[i]; j++)//每个因子的每一项,共有num[i]+1项 { for(int k=0; k<=max; k++)//循环c1数组的每一项 c2[k+j*v[i]] += c1[k]; } max=max1; for(int i=0; i<=max1; i++) c1[i]=c2[i],c2[i]=0;}
对于模板三,就是平常不会经常见到的指数型母函数模板,用处不很大,因为要涉及到阶乘运算,所以数据范围大的话就会溢出;
模板之三如下:
#include <stdio.h>#include <string.h>const int MAX=30;double c1[MAX],c2[MAX];int f[11];void fib(int n)//计算阶乘{ f[0]=1; for(int i=1; i<=n; i++) f[i]=f[i-1]*i;}int main(){ fib(10); int N,M,num[110]; while(~scanf("%d%d",&N,&M)) { for(int i=1; i<=N; i++) scanf("%d",&num[i]); memset(c1,0,sizeof(c1)); c1[0]=1; for(int i=1; i<=N; i++)//循环每个因子 { memset(c2,0,sizeof(c2)); for(int j=0; j<=num[i]&&j<=M; j++) //每个因子的每一项 for(int k=0; k+j<=M; k++) //循环c1数组的每一项 c2[k+j] += (c1[k]/f[j]); memcpy(c1,c2,sizeof(c2)); } printf("%.lf\n",c1[M]*f[M]); } return 0;}
其实这是hdu 1521题,感觉细节很多,就直接全部写上去了,首先 c1,c2为double型;其次,int型最多能存下12!,13!就超int了,long long(__int64)最多能存下20!;
然后就是循环,和普通母函数一样,就计算时略微不同,这个对照上面的指数母函数多项式理解;最后就是输出用double型.lf,应该就这么多了。。。
- 母函数基础
- 母函数 基础
- 基础母函数
- 母函数基础
- 基础母函数模版
- 母函数基础
- 数学基础-母函数
- 母函数 基础入门
- 基础母函数1001
- 基础母函数1002
- 基础母函数1003
- 基础母函数1004
- 基础母函数1005
- NYOJ588(母函数基础)
- 函数基础
- 函数基础
- 函数基础
- 基础函数
- N卡Fermi架构
- stringstream的用法
- LCM调试
- QTcpSocket使用过程中的一些问题记录
- do the little IT bird,and do the best
- 母函数 基础
- 字符串匹配之horspool算法(简化的BM算法)
- 设计模式 装饰者模式 带你重回传奇世界
- hdu 4512 吉哥系列故事——完美队形I_LCIS
- Service Test2
- 数据放入內表错误,at new后出现*解决方法
- manifest文件导致,网狐无法正常工作问题.
- ArcGlobe三维开发之十九——GlobeControl与MapControl的二三维联动
- hdu 3068 最长回文_Manacher模板