(原)关于人民币找零钱的问题

引用请注明出处:http://www.cnblogs.com/lihaiping/p/7799495.html

最近项目开发中遇到一个和找零钱很相似的问题,所以网上搜索了一下,大部分的问题,都是关于如何求出找零钱的方法数(有多少种找零的方法)和如何求少找零的方案。

但我这次的问题,需要在求出找零钱方法数的同时还需要求出这些方法中的每种具体找零方法。

根据网上的代码,求找零方法数种类:(动态规划的算法)

 1 int countWays(vector<int> changes, int n, int x) {
 2     // 待兑换的金额是i,可用的范围是0-j-1
 3     // i = x,j = 0-n-1
 4     //int dp[x+1][n];
 5
 6     //使用动态开辟二维数组
 7     int **dp = new int*[x+1];
 8     for(int i=0;i<(x+1);i++)
 9     {
10         dp[i] = new int[n];
11         memset(dp[i],0,n*sizeof(int));
12     }
13     // 当待兑换的金额是0的时候,都是只有一种,就是空集
14     for(int i=0;i<n;i++){//
15         dp[0][i] = 1;
16     }
17
18     // 第1列,待兑换的钱是i,因为只能用第一种零钱,所以只有当是第一种零钱的整数倍的时候,才有一种兑换方法
19     for (int i = 1; i <= x; i++) {
20         if (i % changes[0] == 0) {
21             dp[i][0] = 1;
22         }
23     }
24     for (int i = 1; i <= x; i++)
25     {
26         for (int j = 1; j < n; j++)
27         {
28             if (i - changes[j] >= 0)
29             {
30                 dp[i][j] += (dp[i][j-1] + dp[i - changes[j]][j]);
31             }
32             else{
33                 dp[i][j] += dp[i][j-1];
34             }
35         }
36     }
37     int count=dp[x][n-1];
38
39
40     for(int k=0;k<(x+1);k++)
41         delete []dp[k];
42
43     delete []dp;
44
45     return count;
46 }

下面为我改造求找零方法数的同时并记录下找零的具体方法:

  1 //map<待兑换金额,map<所用找零的面值,找零具体方案vector<vector<int> > >>
  2 map<int,map<int,vector<vector<int> > > > mapAimChanges;
  3
  4 int countWaysEx(vector<int> changes, int n, int x) {
  5     // 待兑换的金额是i,可用的范围是0-j-1
  6     // i = x,j = 0-n-1
  7     //int dp[x+1][n];
  8
  9     //使用动态开辟二维数组
 10     int **dp = new int*[x+1];
 11     for(int i=0;i<(x+1);i++)
 12     {
 13         dp[i] = new int[n];
 14         memset(dp[i],0,n*sizeof(int));
 15     }
 16
 17
 18
 19     // 当待兑换的金额是0的时候,都是只有一种,就是空集
 20     for(int i=0;i<n;i++){//
 21         dp[0][i] = 1;
 22     }
 23     //mapAimChanges.insert(pair<int,map<int,vector<vector<int> > > >(0,mapVecVecTemp_0));
 24
 25     // 第1列,待兑换的钱是i,因为只能用第一种零钱,所以只有当是第一种零钱的整数倍的时候,才有一种兑换方法
 26      for (int i = 1; i <= x; i++) {
 27         if (i % changes[0] == 0) {
 28             //一维数组,具体找零方案
 29             vector<int> vecTemp(i/changes[0],changes[0]);
 30             //找零方案的组合,形成一个二维数组
 31             vector<vector<int> > vecvecTemp(1,vecTemp);
 32             //存储所用零钱
 33             map<int,vector<vector<int> > > mapVecVecTemp;
 34             mapVecVecTemp.insert(pair<int,vector<vector<int> > >(0,vecvecTemp));
 35
 36             mapAimChanges.insert(pair<int,map<int,vector<vector<int> > > >(i,mapVecVecTemp));
 37
 38             dp[i][0] = 1;
 39         }
 40     }
 41     for (int i = 1; i <= x; i++)
 42     {
 43         for (int j = 1; j < n; j++)
 44         {
 45             if (i - changes[j] >= 0)
 46             {
 47                 //找零方案的组合,二维数组
 48                 vector<vector<int> > vecvecTempGoup;
 49                 //存储所用零钱索引j的找零方案组合
 50                 map<int,vector<vector<int> > > mapVecVecTemp;
 51
 52                 map<int,map<int,vector<vector<int> > > >::iterator iter1=mapAimChanges.find(i);
 53                 if (iter1!=mapAimChanges.end())
 54                 {
 55                     mapVecVecTemp=iter1->second;//进行一次拷贝,防止后续在earse的时候出现其他内容的丢失
 56                     //查找上一个索引j-1
 57                     map<int,vector<vector<int> > >::iterator iter2=iter1->second.find(j-1);
 58                     if (iter2!=iter1->second.end())
 59                     {//如果找到
 60                         //先把j-1的内容拷贝
 61                         vecvecTempGoup=iter2->second;
 62                     }
 63                 }
 64
 65                 //添加新的方案
 66                 vector<vector<int> > vecvecTemp2;//新的找零二维数组方案
 67                 iter1=mapAimChanges.find(i - changes[j]);//查找之前对i-change[j]的找零方案
 68                 if (iter1!=mapAimChanges.end())
 69                 {
 70                     //查找上一个索引j
 71                     map<int,vector<vector<int> > >::iterator iter2=iter1->second.find(j);
 72                     if (iter2!=iter1->second.end())
 73                     {//如果找到
 74                         //对于i-changes[j]的零钱在j这个索引上所用的所有找零方案,
 75                         //我们需要在之前的基础上插入一个新的元素changes[i],形成一个新的找零方案
 76                         vector<vector<int> > vecvecTemp;
 77                         vecvecTemp=iter2->second;
 78
 79                         vector<vector<int> >::iterator vecvecIter3=vecvecTemp.begin();
 80                         for (;vecvecIter3!=vecvecTemp.end();vecvecIter3++)
 81                         {
 82                             vector<int> vecTemp=*vecvecIter3;
 83                             vecTemp.push_back(changes[j]);
 84                             //将生成的新找零方案,放入二维数组
 85                             vecvecTemp2.push_back(vecTemp);
 86                         }
 87                     }
 88                 }
 89                 else//说明找到的是为空集
 90                 {//说明i - changes[j]==0,才会为空集
 91                     vector<int> vecTemp_0(1,changes[j]);
 92                     vecvecTemp2.push_back(vecTemp_0);
 93                 }
 94
 95                 if (!vecvecTemp2.empty())
 96                 {
 97                     vecvecTempGoup.insert(vecvecTempGoup.end(),vecvecTemp2.begin(),vecvecTemp2.end());
 98                 }
 99                 if (!vecvecTempGoup.empty())
100                 {
101                     mapVecVecTemp.erase(j);
102                     mapVecVecTemp.insert(pair<int,vector<vector<int> > >(j,vecvecTempGoup));
103                     mapAimChanges.erase(i);
104                     mapAimChanges.insert(pair<int,map<int,vector<vector<int> > > >(i,mapVecVecTemp));
105                 }
106
107
108                 dp[i][j] += (dp[i][j-1] + dp[i - changes[j]][j]);
109             }
110             else{
111                 //找零方案的组合,二维数组
112                 vector<vector<int> > vecvecTemp;
113                 map<int,map<int,vector<vector<int> > > >::iterator iter1=mapAimChanges.find(i);
114                 if (iter1!=mapAimChanges.end())
115                 {
116                     //存储所用零钱索引j的找零方案组合
117                     map<int,vector<vector<int> > > mapVecVecTemp=iter1->second;
118                     //查找上一个索引
119                     map<int,vector<vector<int> > >::iterator iter2=iter1->second.find(j-1);
120                     if (iter2!=iter1->second.end())
121                     {//如果找到
122                         vecvecTemp=iter2->second;
123                         mapVecVecTemp.insert(pair<int,vector<vector<int> > >(j,vecvecTemp));
124
125                         //map操作的时候,相同的key的时候,会出现insert失败,而不是覆盖
126                         //所以这里需要先进行删除
127                         mapAimChanges.erase(i);
128                         //mapAimChanges.erase(iter1);
129                         mapAimChanges.insert(pair<int,map<int,vector<vector<int> > > >(i,mapVecVecTemp));
130                     }
131                 }
132                 dp[i][j] += dp[i][j-1];
133             }
134         }
135     }
136     int count=dp[x][n-1];
137
138
139     for(int k=0;k<(x+1);k++)
140         delete []dp[k];
141
142     delete []dp;
143
144     return count;
145 }

下面为测试的代码:

 1     vector<int> vecRmb;
 2     vecRmb.push_back(1);
 3     vecRmb.push_back(2);
 4     vecRmb.push_back(3);
 5
 6     int ret=countWays(vecRmb,vecRmb.size(),5);
 7     printf("ret=%d\n",ret);
 8
 9     ret=countWaysEx(vecRmb,vecRmb.size(),5);
10     printf("ret=%d\n",ret);
11     map<int,map<int,vector<vector<int> > > >::iterator map_iter=mapAimChanges.find(5);
12     if (map_iter!=mapAimChanges.end())
13     {
14         map<int,vector<vector<int> > >::iterator map_iter2=map_iter->second.find(vecRmb.size()-1);
15         if (map_iter2!=map_iter->second.end())
16         {
17             vector<vector<int> >::iterator vec_vec_iter3=map_iter2->second.begin();
18             printf("size:%d\n",map_iter2->second.size());
19             for (;vec_vec_iter3!=map_iter2->second.end();vec_vec_iter3++)
20             {
21                 vector<int> vecTemp=*vec_vec_iter3;
22                 for (int i=0;i<vecTemp.size();i++)
23                 {
24                     printf("[");
25                     printf(" %d ",vecTemp.at(i));
26                     printf("]");
27                 }
28                 printf("\n");
29             }
30         }
31
32     }

打印结果:

其中方法和数据结构没有进行优化,如果有优化的方法,各位可以提出来,我们一起改造这个经典问题。

时间: 2024-10-01 19:32:40

(原)关于人民币找零钱的问题的相关文章

人民币找零钱,返回最少张数

/// <summary> /// 找零钱,返回人民币总张数 /// </summary> class MoneyNums { /// <summary> /// 定义人民币类别值 /// </summary> private decimal[] RMB = { 100, 50, 20, 10, 5, 1, 0.5m, 0.1m }; /// <summary> /// 找零钱,返回人民币总张数 /// </summary> ///

c语言趣题之“找零钱的方法数量 ”

/* Name: Copyright: Author: Date: 31-12-14 16:51 Description: 找零钱的方法数量 描述 我们知道人民币有1.2.5.10.20.50.100这几种面值. 现在给你n(1≤n≤250)元,让你计算换成用上面这些面额表示且总数不超过100张,共有几种. 比如4元,能用4张1元.2张1元和1张2元.2张2元,三种表示方法. 输入 输入有多组,每组一行,为一个整合n. 输入以0结束. 输出 输出该面额有几种表示方法. 样例输入 1 4 0 样例

[华为机试练习题]35.找零钱

题目 描述: 我们知道人民币有1.2.5.10.20.50.100这几种面值.现在给你n(1≤n≤250)元,让你计算换成用上面这些面额表示且总数不超过100张,共有几种.比如4元,能用4张1元.2张1元和1张2元.2张2元,三种表示方法. 题目类别: 循环 难度: 初级 运行时间限制: 10Sec 内存限制: 128MByte 阶段: 入职前练习 输入: 输入有多组,每组一行,为一个整合n.输入以0结束. 输出: 输出该面额有几种表示方法. 样例输入: 1 4 0 样例输出: 1 3 代码 /

华为应聘测试题目——找零钱(递归解决)

找零钱 描述: 我们知道人民币有1.2.5.10.20.50.100这几种面值.现在给你n(1≤n≤250)元,让你计算换 成用上面这些面额表示且总数不超过100张,共有几种.比如4元,能用4张1元.2张1元和1张2元.2张2元, 三种表示方法. 题目类别: 循环 难度: 初级 分数:   运行时间限制: 10 Sec 内存限制: 128 MByte 阶段: 招聘管理 输入: 输入有多组,每组一行,为一个整合n.输入以0结束. 输出: 输出该面额有几种表示方法. 样例输入: 1 4 0 样例输出

AOJ 169 找零钱 DP OR 母函数

一直觉得这题因为有总量限制,是不能用母函数解的,今天偶然发现原来是可以的,记录一下. 只要搞母函数的时候多开一维来表示用了多少个硬币就好了,其实就是目标状态是二维的母函数 类似于 假设我现在要处理的面值是2      (1 + x^2 * y + x^4 * y ^ 2 + x ^ 6 * y ^ 3...) 就表示用0个,1个,2个,3个..硬币的状态了. 看来母函数最重要的还是对式子本身的理解,这样才能应对各种变化. #include <cstdio> #include <cstri

贪婪算法_找零钱

贪婪算法是一种求近似解的方法,它存在如下几个问题: 1.不能保证最后的解是最优解. 2.不能求最大解或者最小解问题. 3.只能满足某些约束条件的可行解范围. 下面给出用贪婪算法解决找零钱这一问题的代码: 1 #include<stdio.h> 2 #define max 7 3 float facevalue[max]={50,20,10,5,1,0.5,0.1};//同时是否有无该面值用于找零,也能在此处进行修改 4 int num[max]={0}; 5 float exchange(fl

PAT 乙级 1037 在霍格沃茨找零钱(20)C++版

1037. 在霍格沃茨找零钱(20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 如果你是哈利·波特迷,你会知道魔法世界有它自己的货币系统 -- 就如海格告诉哈利的:"十七个银西可(Sickle)兑一个加隆(Galleon),二十九个纳特(Knut)兑一个西可,很容易."现在,给定哈利应付的价钱P和他实付的钱A,你的任务是写一个程序来计算他应该被找的零钱. 输入格式: 输入在1行中分别给出P和A,

1037. 在霍格沃茨找零钱(20)

1037. 在霍格沃茨找零钱(20) 如果你是哈利·波特迷,你会知道魔法世界有它自己的货币系统 -- 就如海格告诉哈利的:"十七个银西可(Sickle)兑一个加隆(Galleon),二十九个纳特(Knut)兑一个西可,很容易."现在,给定哈利应付的价钱P和他实付的钱A,你的任务是写一个程序来计算他应该被找的零钱. 输入格式: 输入在1行中分别给出P和A,格式为"Galleon.Sickle.Knut",其间用1个空格分隔.这里Galleon是[0, 107]区间内的

1028: 在霍格沃茨找零钱

1028: 在霍格沃茨找零钱 时间限制: 1 Sec  内存限制: 128 MB提交: 316  解决: 147[提交][状态][讨论版] 题目描述 如果你是哈利·波特迷,你会知道魔法世界有它自己的货币系统 —— 就如海格告诉哈利的:“十七个银西可(Sickle)兑一个加隆(Galleon),二十九个纳特(Knut)兑一个西可,很容易.”现在,给定哈利应付的价钱P和他实付的钱A,你的任务是写一个程序来计算他应该被找的零钱. 输入 输入在1行中分别给出P和A,格式为“Galleon.Sickle.