Description
小李是超市的收银员,每当顾客来结账时,他们给的钱往往都多于他们所购物品的实际价格,这时,小李就需要找零给他们。小李是一个很爱思考的人,他想知道在目前的纸币面额情况下(1角、5角、1元、5元、10元、20元、50元、100元),如果每种面额的纸币的数量都是无限的,他要给一个顾客找零N(0<N<100)元有多少种方式(如0.5元有两种方式:5个1角和1个5角)。小李很苦恼这个问题,聪明的你能帮助他吗?
Input
输入包括多组测试用例,通过EOF结束。
每组测试用例包括一行,为一个数N(1<N<100),N为最多包含一位小数的实数。
Output
对于每组测试用例,输出一行,为一个整数,表示找零的方法总数。
Sample Input
0.5
1
Sample Output
2
4
对普通的三、四种货币的找零问题比较简单,只要想法不超时,n重for循环解决
但对于多种货币,那就无法用多重循环。下面有两种方法,我理解的很困难(cry:
方法一:
先看几种基本情况
可以发现分解总是找离它最近的基本数依次递减逐层分解,所以每层都是一个嵌套的情况
#include<stdio.h>
int count=0;
const int A[]={1,5,10,50,100,500,1000};
void change(int x,int top){
printf("%d %d %d\n",x,top,count);
if(x==0){
count++;//递归边界,就是A【top】的组成和与x相同了
return ;
}
if(top<0) return ;//超过了我们基的范围
change(x,top-1);//看下一个基组成x的情况
int i;
for(i=A[top];i<=x;i+=A[top]){
change(x-i,top-1);//看这个A【top】逐递增的被它的下一个基表示的情况
}
}
int main(){
double x;
scanf("%lf",&x);
int m=10*x;
change(m,6);
printf("%d\n",count);
}
方法二:
有点类似方法一的逆运算。
#include<stdio.h>
const int A[]={1,5,10,50,100,500,1000};
int main(){
double x;
int m;
scanf("%lf",&x);
m=x*10;
int a[100]={};
a[0]=1;
int i,j;
for(i=0;i<8;i++){
for(j=1;j<=m;j++){
if(j>=A[i]){//如果比基元大,那么可以说明该基构成该数至少有一种情况
a[j]+=a[j-A[i]];//理解请结合下图
//printf("%d %d\n",j,a[j]);
}
}
}
printf("%d\n",a[m]);
}
以1为例输出
发现1能构成一种情况,构成5有两种情况,所以构成10由于有次基5,和次次基10,所以构成情况有4种。