Recursion 硬币组合问题 @CareerCup
2013-11-27 09:15
447 查看
非常有意义的一道题,关键的一点要知道DFS是有顺序的,即在DFS中(5,1)和(1,5)是不一样的组合。所以对这道题我的第一种解法就重复算了多次,具体如图所示:当计算f(10)时,DFS给出的结果是9次,但实际上应该是4.
去重的方法是多用一个变量(level)来限制条件。这样能保证在访问对于给定level只会深搜小于等于level的分支。
同样参考了http://hawstein.com/posts/8.7.html
“但,这是错误的。问题出在哪?有序与无序的区别!这个函数计算出来的组合是有序的, 也就是它会认为1,5和5,1是不一样的,导致计算出的组合里有大量是重复的。 那要怎么避免这个问题?1,5和5,1虽然会被视为不一样,但如果它们是排好序的, 比如都按从大到小排序,那么就都是5,1了,这时就不会重复累计组合数量。
可是我们总不能求出答案来后再搞个排序吧,多费劲。这时我们就可以在递归上做个手脚, 让它在计算的过程中就按照从大到小的币值来组合。比如, 现在我拿了一个25分的硬币,那下一次可以取的币值就是25,10,5,1;如果我拿了一个 10分的,下一次可以取的币值就只有10,5,1了;这样一来,就能保证,同样的组合, 我只累计了一次”
package Recursion;
/**
* Given an infinite number of quarters (25 cents), dimes (10 cents), nickels (5
* cents) and pennies (1 cent), write code to calculate the number of ways of
* representing n cents.
*
* 译文:
*
* 我们有25分,10分,5分和1分的硬币无限个。写一个函数计算组成n分的方式有几种?
*
*/
public class S9_8 {
public static void main(String[] args) {
System.out.println(recWrong(10));
System.out.println(recCorrect(10, 10));
}
public static int recWrong(int n) {
if (n < 0) {
return 0;
}
if (n == 0) {
return 1;
}
int ways = 0;
ways += recWrong(n - 25);
ways += recWrong(n - 10);
ways += recWrong(n - 5);
ways += recWrong(n - 1);
return ways;
}
// 增加一个level变量来控制重复的问题!
public static int recCorrect(int n, int level) {
if (n < 0) {
return 0;
}
if (n == 0) {
return 1;
}
int ways = 0;
if (level >= 25) {
ways += recCorrect(n - 25, 25);
}
if (level >= 10) {
ways += recCorrect(n - 10, 10);
}
if (level >= 5) {
ways += recCorrect(n - 5, 5);
}
if (level >= 1) {
ways += recCorrect(n - 1, 1);
}
return ways;
}
}
去重的方法是多用一个变量(level)来限制条件。这样能保证在访问对于给定level只会深搜小于等于level的分支。
同样参考了http://hawstein.com/posts/8.7.html
“但,这是错误的。问题出在哪?有序与无序的区别!这个函数计算出来的组合是有序的, 也就是它会认为1,5和5,1是不一样的,导致计算出的组合里有大量是重复的。 那要怎么避免这个问题?1,5和5,1虽然会被视为不一样,但如果它们是排好序的, 比如都按从大到小排序,那么就都是5,1了,这时就不会重复累计组合数量。
可是我们总不能求出答案来后再搞个排序吧,多费劲。这时我们就可以在递归上做个手脚, 让它在计算的过程中就按照从大到小的币值来组合。比如, 现在我拿了一个25分的硬币,那下一次可以取的币值就是25,10,5,1;如果我拿了一个 10分的,下一次可以取的币值就只有10,5,1了;这样一来,就能保证,同样的组合, 我只累计了一次”
package Recursion;
/**
* Given an infinite number of quarters (25 cents), dimes (10 cents), nickels (5
* cents) and pennies (1 cent), write code to calculate the number of ways of
* representing n cents.
*
* 译文:
*
* 我们有25分,10分,5分和1分的硬币无限个。写一个函数计算组成n分的方式有几种?
*
*/
public class S9_8 {
public static void main(String[] args) {
System.out.println(recWrong(10));
System.out.println(recCorrect(10, 10));
}
public static int recWrong(int n) {
if (n < 0) {
return 0;
}
if (n == 0) {
return 1;
}
int ways = 0;
ways += recWrong(n - 25);
ways += recWrong(n - 10);
ways += recWrong(n - 5);
ways += recWrong(n - 1);
return ways;
}
// 增加一个level变量来控制重复的问题!
public static int recCorrect(int n, int level) {
if (n < 0) {
return 0;
}
if (n == 0) {
return 1;
}
int ways = 0;
if (level >= 25) {
ways += recCorrect(n - 25, 25);
}
if (level >= 10) {
ways += recCorrect(n - 10, 10);
}
if (level >= 5) {
ways += recCorrect(n - 5, 5);
}
if (level >= 1) {
ways += recCorrect(n - 1, 1);
}
return ways;
}
}
相关文章推荐
- Recursion 二维空间里机器人向右或向下走的所有路径问题 @CareerCup
- Recursion 爬楼梯问题 @CareerCup
- Recursion 叠箱子最高问题 @CareerCup
- Recursion 八皇后问题 @CareerCup
- Recursion n对括号的组合 @CareerCup
- Recursion 计算表达式的括号组合 @CareerCup
- 【编程之法】硬币面值组合问题
- 【算法27】硬币面值组合问题
- Recursion 图像软件中的“填充”函数 @CareerCup
- 硬币组合问题
- 硬币组合问题
- 硬币组合问题-动态规划
- 钱币组合问题(一):(每种硬币不限次数)
- 硬币组合问题
- 一维数组和二维数组求解硬币组合个数问题
- CareerCup之1.8 字符串移位包含问题
- 硬币组合问题
- 动态规划应用—硬币组合问题
- 钱币组合问题(二):(每种硬币次数受限)
- 回溯法解组合问题——硬币问题