换钱的方法数
来源:互联网 发布:如何编译linux源码 编辑:程序博客网 时间:2024/05/08 16:19
给定数组arr,arr中所有的值都为整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,在给定一个整数aim代表要找的钱数,求换钱的方法有多少种。
方法一:利用递归,时间复杂度O(aim^N)
arr=[10,b,c...], aim=100,分析过程如下:
1.用0张10元的货币,让[b,c......]组成剩下的100,最终方法数记为res1.
2.用1张10元的货币,让[b,c......]组成剩下的90,最终方法数记为res2.
3.用2张10元的货币,让[b,c......]组成剩下的80,最终方法数记为res3.
::::::
10.用10张10元的货币,让[b,c......]组成剩下的0,最终方法数记为res11.
那么res1+res2+res3+......+res11的值就是总的方法数。
int money1(int* arr, int len, int index,int aim){ if(len==0 || aim<0) return 0; int res =0; if(index==len) res = (aim==0?1:0); else { for(int i=0; i*arr[index]<=aim; i++) { res += money1(arr,len,index+1,aim-arr[index]*i); } } return res;}
方法二:动态规划方法,时间复杂度O(N*aim)
生成行数为N、列数为aim+1的矩阵dp,dp[i][j]的含义是在使用arr[0......i]货币的情况下,组成钱数j有多少种方法。dp[i][j]值得求法如下:
1.对于矩阵dp第一列的值dp[..][0],表示组成钱数为0的方法数,很明显是1种,也就是不使用任何货币。所以dp第一列的值统一设置为1.
2. 对于矩阵dp第一行的值dp[0][..],表示只能使用arr[0]这一种货币的情况下,组成钱的方法数,如,arr[0]=10时,能组成的钱数只有10,20,30.......所以,令dp[0][i*arr[0]]=1.
3. 出第一行和第一列外的其他位置,记为位置(i,j).。dp[i][j]的值是以下几个值的累加。
完全不用arr[i]货币,只使用arr[0...i-1]货币时,方法数为dp[i-1][j];
用1张arr[i]货币,剩下的钱用arr[0...i-1]货币组成,方法数为dp[i-1][j-arr[i]];
用2张arr[i]货币,剩下的钱用arr[0...i-1]货币组成,方法数为dp[i-1][j-2*arr[i]];
::::::::
用k张arr[i]货币,剩下的钱用arr[0...i-1]货币组成,方法数为dp[i-1][j-k*arr[i]]; (j-k*arr[i]>=0)
步骤3中,第一种情况方法数为dp[i-1][j],而第二种情况一直到第k种情况的方法数累加值其实就是dp[i][j-arr[i]]的值。所以步骤3可以简化为dp[i][j]=dp[i][j-arr[i]]+dp[i-1][j]
int money2(int* arr, int len, int aim){ if(len==0 ||aim<0) return 0; int **dp; dp = new int*[len]; for(int i=0; i<len; i++) { dp[i]=new int[aim+1]; } for(int i=0; i<len; i++) { dp[i][0]=1; } for(int j=1; j<=aim; j++) { dp[0][j]=0; } for(int j=1; j*arr[0]<=aim; j++) { dp[0][j*arr[0]]=1; } for(int i=1; i<len; i++) { for(int j=1; j<=aim; j++) { if(j>=arr[i] ) { dp[i][j]=dp[i][j-arr[i]]+dp[i-1][j]; } else dp[i][j] = dp[i-1][j]; } } int res = dp[len-1][aim]; for(int i=1; i<len; i++) { delete []dp[aim+1]; } delete []dp; return res;}
方法三:时间复杂度为O(N*aim)的动态规划方法结合空间压缩技巧。额外的空间复杂度降至O(aim)
int money3(int* arr, int len, int aim){ int *dp; dp = new int[aim+1]; dp[0]=1; for(int i=1; i<=aim; i++) { dp[i]=0; } for(int j=1; j*arr[0]<=aim; j++) { dp[j*arr[0]]=1; } for(int i=1; i<len; i++) { for(int j=1; j<=aim; j++) { if(j-arr[i]>=0) { dp[j] = dp[j-arr[i]]+dp[j]; } else dp[j]=dp[j]; } } int res=dp[aim]; return res;}
三种方法的测试:
#include <iostream>#include<stdlib.h>int money1(int* arr, int len, int index,int aim);int money2(int* arr, int len, int aim);int money3(int* arr, int len, int aim);using namespace std;#define maxnum INT_MAX;int main(){ int arr[] = {5,10,25,1}; int aim = 15; size_t arr_len=sizeof(arr)/sizeof(int); int means1 = money1(arr,arr_len,0,aim); int means2 =money2(arr,arr_len,aim); int means3 =money3(arr,arr_len,aim); cout<<"means: "<<means1<<endl; cout<<"means: "<<means2<<endl; cout<<"means: "<<means3<<endl; return 0;}
- 换钱的方法数
- 换钱的方法数
- 换钱的方法数
- 换钱的方法数
- 换钱的方法数
- 换钱的方法数
- 换钱的方法数
- 换钱的方法数
- 求换钱的方法数
- 动态规划解决换钱的方法数
- 动态规划之换钱的最少货币数以及换钱方法数
- 递归与动态规划---换钱的方法数
- 换钱的最少货币数
- 换钱的最少货币数
- 换钱的最少货币数
- 换钱的最少货币数
- 求换钱的最少货币数
- 动态规划之换钱的方法数目
- Java实现RC4加密算法、RSA算法、MD5算法
- jquery serializeobject();方法序列化表单的属性,返回字符串。
- Socket通信,简单的用两个手机实现TCPIP
- C++学习笔记(二):内联函数inline
- 人工智能之机器学习算法体系汇总
- 换钱的方法数
- 如何找出数列中符合条件的数对的个数
- 268. Missing Number
- 简单 Shell 脚本随手录
- easyui设置datebox默认当前日期,且只能选择当前日期之前的日期
- mongoose中connect()、createConnection()和connection的区别和作用
- javascript学习笔记:BOM对象(存疑)
- ARM-Linux移植之(一)——内核启动流程分析
- 一些精致的web UI框架及常用前端UI框架