华为面试2:1分2分5分的硬币,组成1角,共有多少种组合。

转载自:http://blog.csdn.net/iamzhaiwei/article/details/7718000

动态规划,注意不要有重复的,例如组成1角钱,5 2 2 1 和 1 2 2 5是1种组合

算法的设计思想在程序中注释的很清楚。

解法一:

[cpp]  view plain copy
  1. // 动态规划  
  2. // total_money: 要找的零钱总和  
  3. // changes: 零钱数组,已经从小到大排序,第1个元素设为0,有效元素从第2个位置即下标1开始  
  4. // kinds_change: 零钱种类  
  5. int make_change_problem(int total_money, int *changes, int kinds_change)  
  6. {  
  7.     // opt[i][j]表示用前j种零钱组成i元钱的组合数目,第j种零钱的数目可以为0  
  8.     boost::multi_array<int, 2> opt(boost::extents[total_money+1][kinds_change+1]);  
  9.     int i, j;  
  10.     // 组成0元钱的组合数目只有1种,即不选择任何零钱  
  11.     i = 0;  
  12.     for (j = 0; j <= kinds_change; ++j)  
  13.         opt[i][j] = 1;  
  14.     // 用0种零钱组成i(1<=i<=total_money)元钱的组合数目是0  
  15.     j = 0;  
  16.     for (i = 1; i <= total_money; ++i)  
  17.         opt[i][j] = 0;  
  18.     for (i = 1; i <= total_money; ++i)  
  19.     {  
  20.         for (j = 1; j <= kinds_change; ++j)  
  21.         {  
  22.             opt[i][j] = 0;  
  23.             int K = i / changes[j]; // 第j种零钱的最大数目  
  24.             for (int k = 0; k <= K; ++k)  
  25.                 opt[i][j] += opt[i-k*changes[j]][j-1];  
  26.         }  
  27.     }  
  28.     return opt[total_money][kinds_change];  
  29. }  
  30.   
  31. int main(int argc, char **argv)  
  32. {  
  33.     int total_money = 10;  
  34.     int changes[] = {0, 1, 2, 5};  
  35.     int kinds_change = sizeof(changes) / sizeof(int) - 1;  
  36.     int number;  
  37.     number = make_change_problem(total_money, changes, kinds_change);  
  38.     cout << number << endl;  
  39.     return 0;  
  40. }  


解法二:

[cpp]  view plain copy
  1. // total_money: 要找的零钱总和  
  2. // changes: 零钱数组,已经从小到大排序,第1个元素设为0,有效元素从第2个位置即下标1开始  
  3. // kinds_change: 零钱种类  
  4. int make_change_problem_v2(int total_money, int *changes, int kinds_change)  
  5. {  
  6.     // opt[i]表示i元钱的组合数目  
  7.     std::vector<int> opt(total_money+1, 0);  
  8.       
  9.     // 组成0元钱的组合数目只有1种,即不选择任何零钱  
  10.     opt[0] = 1;  
  11.       
  12.     // 第一个循环计算包含第i种零钱时j元钱的组合数目,第二个循环计算j(j>=changes[i])元钱的组合数目  
  13.     for (int i = 1; i <= kinds_change; ++i)  
  14.     {  
  15.         for (int j = changes[i]; j <= total_money; ++j)  
  16.         {  
  17.             opt[j] += opt[j-changes[i]];  
  18.         }  
  19.     }  
  20.     return opt[total_money];  
  21. }  
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值