题目描述:给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示方法
思路:
一开始我想既然可以递归,那么加备忘或者自底向上DP就可以了,于是出现如下代码
1 //有可能有重复计算,所以这个方法不可行 2 int dp[10000]; 3 int fun(int n) 4 { 5 int i; 6 dp[0] = 1; 7 for(i = 1 ; i <= n ; ++i) 8 { 9 dp[i] = 0; 10 dp[1] = 1; 11 dp[5] = 2; 12 dp[10] = 5; 13 if(i >= 1) 14 { 15 dp[i] += dp[i-1]*dp[1]; 16 } 17 if(i >= 5) 18 { 19 dp[i] += dp[i-5]*dp[5]; 20 } 21 if(i >= 10) 22 { 23 dp[i] += dp[i-10]*dp[10]; 24 } 25 if(i >= 25) 26 { 27 dp[i] += dp[i-25]*dp[25]; 28 } 29 } 30 return dp[n]; 31 }
然后再计算dp[10]的时候,发现,直接dp计算的话有很多重复计算。结果不正确。
于是就采用下面的递归算法。
1 int fun_2(int n,int d) 2 { 3 int next_d; 4 switch(d) 5 { 6 case 25: 7 next_d = 10; 8 break; 9 case 10: 10 next_d = 5; 11 break; 12 case 5: 13 next_d = 1; 14 break; 15 case 1: 16 return 1; 17 } 18 int way = 0; 19 int i; 20 for(i = 0 ; i*d <= n ;++i) 21 { 22 way += fun_2(n-i*d,next_d); 23 } 24 return way; 25 } 26 27 int main() 28 { 29 cout<<fun_2(100,25)<<endl; 30 return 0; 31 }
其实具体思路也就是:对于n,采用1~i个25后,n-i*25用10、5和1分能表示的方法数;采用i个25和j个10后,n-i*25-j*10采用5和1分能表示的方法数;...依次递归即可