整币兑零

来源:互联网 发布:爱知产业大学 推荐 编辑:程序博客网 时间:2024/06/05 01:13

整币兑零是一个特殊的分解统计案例,其不同的的兑换种类与零币的种类及各零币的具体数值密切相关;

本节探讨特定的6种零币与一般从键盘输入的m种零币的两类兑零统计;


特定整币兑零

把一张1元整币兑换成1分,2分,5分,1角,2角和5角共6种零币,共有多少种不同兑换种数?

一般地,把一张二元整币,5元整币或一张n元整币兑换成1分,2分,5分,1角,2角和5角共6种零币,共有多少种不同兑换种数?

1.说明:

一般地设整币的面值为n个单位,面值为1、2、5、10、20、50单元零币的个数分别为p1、p2、p3、p4、p5、p6;

显然需要解一次不定方程:

  • p1+2*p2+5*p3+10*p4+20*p5+50*p6=n

其中p1、p2、p3、p4、p5、p6为非负整数;

对这六个变量实施枚举,确定枚举范围为:

0<=p1<=n0<=p2<=n/20<=p3<=n/5
0<=p4<=n/100<=p5<=n/20,**0<=p6<=n/50
**;

在以上枚举的6重循环中,若满足条件p1+2*p2+5*p3+10*p4+20*p5+50*p6=n,则为一种兑零方法,输出结果并通过变量m统计不同的兑换种类;

2.程序设计:

#include<stdio.h>#include<math.h>int main(){   int p1,p2,p3,p4,p5,p6,n;   long m;   printf("请输入整币量n:");   scanf("1分  2分  5分  1角  2角  5角 \n");   for(p1=0;p1<=n;p1++)    for(p2=0;p2<=n/2;p2++)     for(p3=0;p3<=n/5;p3++)      for(p4=0;p4<=n/10;p4++)       for(p5=0;p5<=n/20;p5++)        for(p6=0;p6<=n/50;p6++)           if(p1+2*p2+5*p3+10*p4+20*p5+50*p6==n)  /*根据条件检验*/           {              m++;              printf("%5d%5d%5d",p1,p2,p3);              printf("%5d%5d%5d\n",p4,p5,p6);           }   printf("%d(1,2,5,10,20,50)=%ld \n",n,m);}

3.程序运行示例及其注意事项:

请输入整币量n:1001分  2分  5分  1角  2角  5角0    0    0   0    0    20    0    0   0    5    00    0    0   1    2    1......100(1,2,5,10,20,50)=4562共有4562个解,即有4562种不同的兑换种数。

注意:当输入数值过大时,兑换种数相应越多,时间也就越长

精简枚举循环设计

1.说明:

在上述程序的6重循环中,我们可精简p1循环,在循环内应用:

  • p1=n-(2*p2+5*p3+10*p4+20*p5+50*p6)

p1赋值,如果p1为非负数,对应一种兑换法;

当n较大时程序运行时间较长,主要是每一个解都要打印,如果只需要计算兑换种数,则可省略打印语句,这样可大大缩减程序的运行时间;

2.程序设计:

#include<stdio.h>#include<math.h>int main(){   int p1,p2,p3,p4,p5,p6,n;   long m;   printf("请输入整币量n:");   scanf("%d",&n);   for(p2=0;p2<=n/2;p2++)    /*已省略p1循环*/     for(p3=0;p3<=n/5;p3++)      for(p4=0;p4<=n/10;p4++)       for(p5=0;p5<=n/20;p5++)        for(p6=0;p6<=n/50;p6++)        {              p1=n-(2*p2+5*p3+10*p4+20*p5+50*p6);  /*p1为一分币的个数*/           if(p1>=0)              m++;     /*用m统计兑换种数*/        }   printf("%d(1,2,5,10,20,50)=%ld \n",n,m);}

3.程序运行示例及其注意事项:

请输入整币量n:200200(1,2,5,10,20,50)=69118
进一步优化枚举设计

1.说明:

以上程序的循环次数已经大大精简,进一步分析,可以看到在程序的循环设计设置中p3循环可从0~n/5改进为0~(n-2*p2)/5,因为在n中p2已占去了2*p2,以此类推,对p4、p5、p6的循环可作类似的循环参量优化;

2.程序设计:

#include<stdio.h>int main(){   int p1,p2,p3,p4,p5,p6,n;   long m=0;   printf("请输入整币量n:");   scanf("%d",&n);   for(p2=0;p2<=n/2;p2++)    for(p3=0;p3<=(n-2*p2)/5;p3++)     for(p4=0;p4<=(n-2*p2-5*p3)/10;p4++)      for(p5=0;p5<=(n-2*p2-5*p3-10*p4)/20;p5++)       for(p6=0;p6<=(n-2*p2-5*p3-10*p4-20*p5)/50;p6++)       {          p1=n-(2*p2+5*p3+10*p4+20*p5+50*p6);          if(p1>=0)             m++;  /*用m统计兑换种数*/       }   printf("%d(1,2,5,10,20,50)=%ld \n",n,m);}

3.程序运行示例及其注意事项:

请输入整币量n:500500(1,2,5,10,20,50)=3937256

注意:以上3个设计尽管都是枚举,但循环的设置与循环参量的改进可精简去一些不必要的比较操作,可大大缩减程序的运行时间


一般整币兑零

把整币兑零的零币一般化为m种,每一种零币值从键盘输入;

1.说明:

因为零币的种类较多时,应用枚举显然不能胜任,考虑应用递推求解,应用递推求解的关键在于寻求递推关系;

设整币为n个单位,m种指定零币从小到大分别为x1,x2,……,xm个单位,整币兑零实际上是一个整体数无序可重复化零问题;

记a(j,i)为整体数是i,最大零数是xj的化零种数,当去掉一个xj后,整体数变为p=i-xj,最大零数可为x1,或x2,……,或xj(因为可重复),于是有递推式:

  • a(j,i)=a(1,p)+a(2,p)+……+a(j,p) (其中p=i-xj)

可据整体数i能否被x1整除确定初始条件:

  • a(1,i)=1 (当i能被x1整除时)

  • a(1,j)=0 (当i不能被x1整除时)

作以上函数递推,分别计算得a(1,n),a(2,n),……,a(m,n),求和即得所求的整币兑零种数:

  • n(x1,x2,……,xm)=a(1,n)+a(2,n)+……+a(m,n)

应用函数递推简化了化零的难度;

2.程序设计:

#include<stdio.h>int main(){   int p,i,j,n,m,k;   static int x[12];   static long int a[12][1001];   long b,s;   printf("请输入整币值(单位数):");  /*输入处理数据*/   scanf("%d",&n);   printf("请输入零币种数:");   scanf("%d",&m);   printf("(从小到大依次输入每种零币值)\n");   for(i=1;i<=m;i++)   {      printf("第%d种零币值(单位数):",i);      scanf("%d",&x[i]);   }   for(i=0;i<=n;i++)    /*确定初始条件*/      if(i%x[1]==0)         a[1][i]=1;      else         a[1][i]=0;   for(s=a[1][n],j=2;j<=m;j++)    /*递推计算a(2,n),a(3,n),...*/   {      for(i=x[j];j<=n;i++)      {         p=i-x[j];         b=0;         for(k=1;k<=j;k++)            b+=a[k][p];         a[j][i]=b;      }      s+=a[j][n];            /*累加a(1,n),a(2,n),...*/   }   printf("整币兑零种数为:%ld\n",s);   /*输出兑零种数*/}

3.程序运行示例及其注意事项:

请输入整币值(单位数):1000请输入零币种数:9(从小到大依次输入每种零币值)第1种零币值(单位数):1第2种零币值(单位数):2第3种零币值(单位数):5第4种零币值(单位数):10第5种零币值(单位数):20第6种零币值(单位数):50第7种零币值(单位数):100第8种零币值(单位数):200第9种零币值(单位数):500整币兑零种数为:327631321

这一问题如果应用前面的枚举设计求解,显然难以胜任;

注意:本程序是求解整币兑零,事实上输入的整币值并不限于实际的100、500、200、1000等,可输入234、5017等任意整数“整币值”,输入的零币值也不受实际约束,只要小于整币值的任意整数即可

1 0
原创粉丝点击