一、 问题描述
给定一个整数N,求解该整数最少能用多少个Fib数字相加得到
Fib数列,就是如: 1,1,2,3,5,8,13…
Fib数列,满足条件:Fib(n)=Fib(n-1)+Fib(n-2) Fib(0)=1 Fib(1)=1;Fib数字,就是Fib数列中的某个数。
比如70 = 55+13+2,即一共用了3个fib数字得到
二、问题求解
1、求出所有小于等于N的Fib数字
//获得小于等于n的所有fib数
private static ArrayList<Integer> getFibs(int n){
ArrayList<Integer> fibs = new ArrayList<Integer>();
int fib1 = 1;
int fib2 = 1;
fibs.add(fib1);
fibs.add(fib2);
int fibn;
while((fibn = fib1 + fib2) <= n)
{
fibs.add(fibn);
fib1 = fib2;
fib2 = fibn;
}
return fibs;
2、转化为一个"完全0-1背包问题"
所谓完全0-1背包问题是指:每个物品可以重复地选择。而这里,每个Fib数字则可以重复地选择。
如:70=34+34+2,34就选择了两次,fib(i) 最多可选择的次数是:N/fib(i),也就是说:将某个Fib数字拆分成(复制成)多个相同与原来值相同的Fib数字。这样,就相当于每个数字只能够选一次,即要么选择它、要么不选择它。
这样,就将完全0-1背包问题转化成普通的0-1背包问题。
这样,就可以把上面求得的ArrayList中存在的Fib数字“扩充”成具有重复Fib数字的ArrayList
比如,对于70而言:扩充后的fib数组为:会有70个1,70/2个 2 …
0-1背包的理解会在另外给出
//完整的代码
import java.util.ArrayList;
public class Solution {
//获得小于等于n的所有fib数
private static ArrayList<Integer> getFibs(int n){
ArrayList<Integer> fibs = new ArrayList<Integer>();
int fib1 = 1;
int fib2 = 1;
fibs.add(fib1);
fibs.add(fib2);
int fibn;
while((fibn = fib1 + fib2) <= n)
{
fibs.add(fibn);
fib1 = fib2;
fib2 = fibn;
}
return fibs;
}
//将之转化成 可重复选择的 0-1 背包问题
private static ArrayList<Integer> augument(ArrayList<Integer> fibs, int n){
ArrayList<Integer> dupfibs = new ArrayList<Integer>();
for (Integer integer : fibs) {
int times = n/integer;//每个fib数字最多可选择多少次
for(int i = 1; i <= times; i++)
dupfibs.add(integer);//"拆分"fib数字
}
return dupfibs;
}
//贪心算法,每次贪心选择最靠近
private static int dp(ArrayList<Integer> dupfibs, int n){
int currentSum = 0;
int count = 0;//需要使用的fib数字 个数
while(currentSum != n){
for(int i = dupfibs.size()-1; i >= 0; i--){
currentSum += dupfibs.get(i);
count++;//表示选择了这个fib数
if(currentSum > n)
{
currentSum -= dupfibs.get(i);
count--;//选择的fib数相加之后越过了n,因此不能选择它
}
}
}
return count;
}
//功能入口
public static int function(int n){
ArrayList<Integer> fibs = getFibs(n);
fibs = augument(fibs, n);
int result = dp(fibs, n);
return result;
}
//test
public static void main(String[] args) {
int result = function(70);
System.out.println(result);
}
}