整数拆分(找零钱)

///
//
// 2007-07-11
// By Rappizit@yahoo.com.cn
//
// 问题描述:
// 若有人民币 1 元 3 张, 2 元 2 张, 5 元 1 张, 10 元 1 张, 50 元 1 张,问能组成多少种币值?各有多少种方案?
//
// 解法描述:
// 根据给定的各种人民币的面值和数目,构造母函数
// F(x) = (1 + x + x^2 + x^3) (1 + x^2 + x^4) (1 + x^5) (1 + x^10) (1 + x^50)
// 展开该母函数,则对于项 x^k , k 为组成的币值,其系数为组成该币值的方案数。例如, 3x^57 表示组成 57 元币值有
// 3 种方案: 50 + 5 + 2 ; 50 + 5 + 1 + 1 ; 50 + 2 + 2 + 1 + 1 + 1 。
//
///

 


#include 
< iostream >
using   namespace  std;

#define  MAX 100     //  最多有 MAX 种不同面值的人民币

void  CaseOfValue ( int  Value [],  int  Count [],  int  Size,  int  Result [],  int  Length)
{
    
int i, j, k, n1, n2, Switch;
    
int* Poly [2];
    Poly [
0= new int [Length];    // Poly [Switch] [] 保存被乘(多项)式的系数
    Poly [1= new int [Length];    // Poly [1 - Switch] []保存积(多项)式的系数    
    
    
// 将 1 作为初始的被乘(多项)式,系数保存于 Poly [0] []
    Poly [0] [0= 1;
    
for (i = 1; i < Length; i ++)
        
{
        Poly [
0] [i] = 0;
        }

    Switch 
= 0;
    n1 
= 0;    // n1 为被乘(多项)式的次数

    
// 迭代地计算积(多项)式
    for (i = 0; i < Size; i ++)
        
{
        n2 
= n1 + Value [i] * Count [i];    // n2 为积(多项)式的次数
        
// 积(多项)式初始化为 0
        for (j = 0; j <= n2; j ++)
            
{
            Poly [
1 - Switch] [j] = 0;
            }

        
// 用乘(多项)式的各项(高次到低次)分别乘以被乘(多项)式的各项(高次到低次)
        
// 然后累加到积(多项)式
        for (j = Value [i] * Count [i]; j >= 0; j -= Value [i])
            
{
            
for (k = n1; k >= 0; k --)
                
{
                Poly [
1 - Switch] [k + j] += Poly [Switch] [k];
                }

            }

        n1 
= n2;
        Switch 
= 1 - Switch;
        }


    
// 将最终的结果多项式的系数复制到 Result []
    for (i = 0; i < Length; i ++)
        
{
        Result [i] 
= Poly [Switch] [i];
        }


    delete Poly [
0];
    delete Poly [
1];
    
return;
}


void  main ()
{
    
int i, cnt = 0, Size = 0, Length = 0;
    
int Value [MAX], Count [MAX], *Result;    
    
while (Size <= 0)
        
{
        cin 
>> Size;    // 输入人民币种类数目
        }

    
for (i = 0; i < Size; i ++)
        
{
        cin 
>> Value [i] >> Count [i];    // 输入每种人民币的面值及数目
        Length += Value [i] * Count [i];
        }

    Length 
++;

    Result 
= new int [Length];
    CaseOfValue (Value, Count, Size, Result, Length);

    cout 
<< "Value Case ";
    
for (i = 0; i < Length; i ++)
        
{
        
if (Result [i])
            
{
            cout 
<< i << ' ' << Result [i] << ' ';
            cnt 
++;
            }

        }

    cout 
<< "Value Count : " << cnt << endl;
    delete Result;
}

 



//
// 测试数据:
// 3
// 1 3
// 2 1
// 3 1
//
// 测试结果:
// Value   Case
// 0       1
// 1       1
// 2       2
// 3       3
// 4       2
// 5       3
// 6       2
// 7       1
// 8       1
// Value Count : 9
//
// 事实上,将整数 k 不限制地拆分,可输入 k 种人民币的面值 Value [1..k] 及数目 Count [1..k],
// 对于 1 <= i <= k , Count [i] = (int)(Value [i] / k) ,则从测试结果的 Value 一栏找到 k ,
// 对应的 Case 数目即为拆分方法数。
// 当要求 k 拆分成的数有限制,或全为奇数,或者全为偶数,或者有最大限制,那么适当改变人民币的面值和数目即可。
// 但是此程序不能求出拆分方式。
//
/// 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值