问题描述:有n个正整数, 按从小到大的顺序升序排列, 现给定一个实数m, 请从数组中找出若干个数, 满足这若干个数的和与m最为接近.
问题分析:该问题实际是背包问题的一个变种. 考虑是否取当前数的策略, 问题可以转化为取当前值和不取当前值的区别.
- 如果取当前值, 算法为 sumAppFix(m, sum+a[i]).
- 如果不取当前值, 算法为sumAppFix(m, sum).
参考java代码如下:
private static Stack<Integer> stack = new Stack<Integer>();
private static Stack<Integer> min_stack = new Stack<Integer>();
public static int[] sumAppFix = {1,4,5,6,10};
public static int min_diff = sumAppFix[sumAppFix.length-1];
public static void sumAppFix(int M, int index, int curSum){
// 若当前和与m的差值小于最小差值, 更新最小差值为当前差值. 并将栈内元素保存在最小栈中.
if(Math.abs(M - curSum) < min_diff){
min_diff = Math.abs(M - curSum);
min_stack = (Stack<Integer>) stack.clone();
}
// 若索引大于数组长度, 返回
if( index >= sumAppFix.length){
return;
}
stack.push(sumAppFix[index]); // 如果包含当前元素,将其压入栈中.
sumAppFix(M, index+1, curSum+sumAppFix[index]); // 若当前元素包含在内, 判断下一个元素.
stack.pop(); // 若不包含当前元素, 将其从栈中删除.
sumAppFix(M, index+1, curSum); // 若不包含当前元素, 判断下一个元素.
}
// 测试函数
public static void main(String[] args) {
sumAppFix(20, 0, 0);
for ( int i:min_stack){
System.out.println(i);
}
}