有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱,求有多少种组合可以组合成n分钱?
方案一:
for()循环嵌套
public class Coin
{
public static void main(String [] args)
{
int sum=0;
System.out.println("Input a number is n:"); //输入一个n的值
Scanner input = new Scanner(System.in);
int n=input.nextInt();
for(int i=0;i<=n/10;i++) // 10 分 的个数
for(int j=0;j<=(n-10*i)/5;j++) //5分 的个数
for(int m=0;m<=(n-10*i-5*j)/2;m++) // 2 分的个数
for(int t=0;t<=n-10*i-5*j-2*m;t++) // 1分的个数
if(10*i+5*j+2*m+t==n) // 判断是不是 相等
System.out.println(sum);
}
}
方案2:
- int
count=0; - int
Target=0; -
- int
coin[4]={1,2,5,10}; - int
total=0; - vector<<span class="datatypes" style="margin: 0px; padding: 0px; border: none; color: rgb(46, 139, 87); background-color: inherit; font-weight: bold; ">int>
solution; -
- void
dfs(int index) - {
-
if( total == Target ) -
{ -
count++; -
cout << count <<":" ; -
for( int i=0; i<(int)solution.size(); i++) -
{ -
cout << solution[i]<<" "; -
} -
cout << endl; -
return; -
} -
-
if( total > Target ) -
return; -
-
for( int i=index; i<4; i++) -
{ -
total += coin[i]; -
solution.push_back( coin[i] ); -
dfs(i); -
solution.pop_back(); -
total -=coin[i]; -
} - }
-
-
-
while(1) -
{ -
count=0; -
cin >> Target; -
dfs(0); -
cout << count <<endl; -
} - 刚一同事说使用 动态规划和母函数来求解,呵呵,听起来不错!
从递推关系说起
研究以下等式:
可以看出:
x2项的系数a1a2+a1a3+...+an-1an中所有的项包括n个元素a1,a2, …an中取两个组合的全体;同理x3项系数包含了从n个元素a1,a2, …an中取3个元素组合的全体。以此类推。
若令a1=a2= …=an=1,在(2-1-1)式中a1a2+a1a3+...+an-1an项系数中每一个组合有1个贡献,其他各项以此类推。故有:
对于序列a0,a1,a2,…构造一函数:
称函数G(x)是序列a0,a1,a2,…的母函数
For example:
(1+x)n是序列C(n,0),C(n,1),...,C(n,n)的母函数。
如若已知序列a0,a1,a2,…则对应的母函数G(x)便可根据定义给出。
反之,如若已经求得序列的母函数G(x),则该序列也随之确定。
序列a0,a1,a2,…可记为{an} 。
实 例 分 析
例一、若有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?各有几种可能方案?
如何解决这个问题呢?考虑构造母函数。
如果用x的指数表示称出的重量,则:
1个1克的砝码可以用函数1+x表示,
1个2克的砝码可以用函数1+x2表示,
1个3克的砝码可以用函数1+x3表示,
1个4克的砝码可以用函数1+x4表示
几种砝码的组合可以称重的情况,可以用以上几个函数的乘积表示:
(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克,系数便是方案数。
(1+x)n是序列C(n,0),C(n,1),...,C(n,n)的母函数。
反之,如若已经求得序列的母函数G(x),则该序列也随之确定。
实 例 分 析
例一、若有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?各有几种可能方案?
如何解决这个问题呢?考虑构造母函数。
如果用x的指数表示称出的重量,则:
1个1克的砝码可以用函数1+x表示,
1个2克的砝码可以用函数1+x2表示,
1个3克的砝码可以用函数1+x3表示,
1个4克的砝码可以用函数1+x4表示
几种砝码的组合可以称重的情况,可以用以上几个函数的乘积表示:
(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分的邮票贴出不同数值的方案数。
因邮票允许重复,故母函数为
例二、求用1分、2分、3分的邮票贴出不同数值的方案数。
因邮票允许重复,故母函数为
以展开后的x4为例,其系数为4,即4拆分成1、2、3之和的拆分数为4,即
4=1+1+1+1=1+1+2=1+3=2+2
概念:整数拆分
所谓整数拆分即把整数分解成若干整数的和,相当于把n个无区别的球放到n个无标志的盒子,盒子允许空着,也允许放多于一个球。整数拆分成若干整数的和,办法不一,不同拆分法的总数叫做拆分数。
例3:若有1克砝码3枚、2克砝码4枚、4克砝码2枚,问能称出哪几种重量?各有几种方案?
例4: 整数n拆分成1,2,3,…,m的和,求其母函数。如若其中m至少出现一次,其母函数又如何?
请自己写出以上两个问题的母函数。
如何编写程序
实现母函数的应用呢?
关键:对多项式展开
以整数拆分为例:
观察以下的母函数:
代码如下:
#include<iostream>
using namespace std;
int main()
{
int a[121],b[121],i,j,k,n;
while(cin>>n)
{
for(i=0;i<=n;i++)
{
b[i]=0;
a[i]=1;//初始化a,由母函数(1+x+x^2+..x^n)初始化,把0-n系数初始化为1
}
for(i=2;i<=n;i++)//i表示的是第i个表达式(母函数的相乘的那个表达式),从2遍历到n
{
for(j=0;j<=n;j++)//j表示的是第i个表示中第j个数,如(1+x+x^2+x^3+…) j=2;j表示的是x^2;
for(k=0;k+j<=n;k+=i)//k表示的是第j的指数,所以每次k值增i(因为第i个表达式增值为i)
b[j+k]+=a[j];
for(k=0;k<=n;k++)
a[k]=b[k],b[k]=0;
}
cout<<a[n]<<endl;
}
}
using namespace std;
int main()
{
}