一、母函数
1.结构
对于序列
a
0
a_0
a0、
a
1
a_1
a1……
a
k
a_k
ak构造一个函数G(x),
G(x) =
a
0
a_0
a0 +
a
1
a_1
a1x +
a
2
a_2
a2
x
2
x^2
x2 +……
a
k
a_k
ak*
x
k
x^k
xk
则称G(x)为序列
a
0
a_0
a0、
a
1
a_1
a1……
a
k
a_k
ak的母函数
2.思想
把组合问题的加法法则和幂级数的的乘幂的相加对应起来.
把每种物品的所有情况枚举出来,并以幂函数的形式表示出来,将这个幂函数作为多项式里面的一个项,最后将多项式展开的结果就反应了各种组合的结果。
这种方法的复杂度为 O( n 3 n^3 n3)
二、个数有限,求组合可能
硬币问题,个数有限求可表示数值
有面值为1、2、5的硬币,各自有1、1、3枚,求可以组合的可能。
对于一个组合的结果来说,其实是由三种硬币的不同的不同取法。
第一种可以取0、1;
第二种可以取0、1、2;
第三种可以取0、1、2、3、4、5;
使用母函数,处理问题:
指数意味着对该种物品的价值。
(
x
0
x^0
x0+
x
1
x^1
x1) (
x
0
x^0
x0+
x
2
x^2
x2+
x
4
x^4
x4) (
x
0
x^0
x0+
x
5
x^5
x5+
x
10
x^{10}
x10+
x
15
x^{15}
x15+
x
20
x^{20}
x20+
x
25
x^{25}
x25)
将多项式展开就可以得到不同价值以及对应价值组合的方案数。
#include<bits/stdc++.h>
using namespace std;
const int N = 10000;
int c1[N];
int c2[N];
int main(){
int a[3];
int num[3]={1,2,5};
while(cin>>a[0]>>a[1]>>a[2]){
memset(c1,0,sizeof(c1));
if(a[0]==0&&a[1]==0&&a[2]==0)
continue;
c1[0]=1;
int maxx=0;
for(int i=0;i<3;i++){//每个因子循环
maxx+=a[i]*num[i];
for(int j=0;j<=maxx;j++){//因子内每一个项循环
for(int k=0;k<=num[i]*a[i]&&k+j<=maxx;k+=num[i]){//与另一个式子相乘循环
c2[k+j]+=c1[j];//将左括号内的值化入右括号中 ,形成一个指数范围到maxx的括号
}
}
memcpy(c1,c2,sizeof(c2));
memset(c2,0,sizeof(c2));
}
int i=0;
while(c1[i])
i++;
printf("%d\n",i);
}
return 0;
}
三、个数不限,求方案数
整数划分
此时会先给定目标 n ,求组合成目标的方案数。
第 i 个物品价值为 v[i] ,最多由
n
/
v
[
i
]
n/v[i]
n/v[i]个物品组成,所以仍然可以把其化为上面那种问题。
然后思路相同。
#include<bits/stdc++.h>
using namespace std;
const int N=10000;
int c1[N+1],c2[N+1];
int main(){
int n;
while(cin>>n){
for(int i=0;i<=n;i++){
c1[i]=c2[i]=0;
}
for(int i=0;i<=n;i++){
c1[i]=1;
}
for(int i=2;i<=n;i++){
for(int j=0;j<=n;j++)
for(int k=0;k+j<=n;k+=i){
c2[j+k]+=c1[j];
}
for(int j=0;j<=n;j++){
c1[j]=c2[j];
c2[j]=0;
}
}
cout<<c1[n]<<endl;
}
}
四、代码模板
思路
把括号从前往后处理,逐步化去。
#include<bits/stdc++.h>
using namespace std;
const int N=10000;
int c1[N+1],c2[N+1];
int main(){
int n;
while(cin>>n){
for(int i=0;i<=n;i++){
c1[i]=c2[i]=0;
}
for(int i=0;i<=n;i++){
c1[i]=1;
}
for(int i=2;i<=n;i++){
for(int j=0;j<=n;j++)
for(int k=0;k+j<=n;k+=i){
c2[j+k]+=c1[j];
}
for(int j=0;j<=n;j++){
c1[j]=c2[j];
c2[j]=0;
}
}
cout<<c1[n]<<endl;
}
}