找零问题多解

Description

小李是超市的收银员,每当顾客来结账时,他们给的钱往往都多于他们所购物品的实际价格,这时,小李就需要找零给他们。小李是一个很爱思考的人,他想知道在目前的纸币面额情况下(1角、5角、1元、5元、10元、20元、50元、100元),如果每种面额的纸币的数量都是无限的,他要给一个顾客找零N(0

Input

输入包括多组测试用例,通过EOF结束。
每组测试用例包括一行,为一个数N(1

Output

对于每组测试用例,输出一行,为一个整数,表示找零的方法总数。

Sample Input

0.5
1

Sample Output

2
4

对普通的三、四种货币的找零问题比较简单,只要想法不超时,n重for循环解决

找零问题多解_第1张图片

但对于多种货币,那就无法用多重循环。下面有两种方法,我理解的很困难(cry:

方法一:

先看几种基本情况

找零问题多解_第2张图片

 可以发现分解总是找离它最近的基本数依次递减逐层分解,所以每层都是一个嵌套的情况

#include
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
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为例输出

找零问题多解_第3张图片发现1能构成一种情况,构成5有两种情况,所以构成10由于有次基5,和次次基10,所以构成情况有4种。

 

你可能感兴趣的:(c++,开发语言,后端)