Fibonacci序列是从0和1开始,然后加上最后两个数字得到下一个数字。
所有正整数都可以表示为一组Fibonacci数的总和而不重复。例如:13可以是集合{13},{5,8}或{2,3,8}的总和。但是,正如我们所看到的,一些数字有多个集合,其总和是数字。如果我们添加约束集不能有两个连续的Fibonacci数,那么我们每个数字都有一个唯一的表示。
我们将使用二进制序列(只有零和1)来做到这一点。例如,17 = 1 + 3 + 13.然后,17 = 100101.详细说明请参见图2.
我想将一些整数转换为这种表示,但整数可能非常大。如何有效地做到这一点。
答案 0 :(得分:3)
问题本身很简单。你总是选择最小的斐波纳契数小于余数。你可以忽略带有连续数字的约束(因为如果你需要两者,下一个是两者的总和,所以你应该选择那一个而不是前两个)。
所以问题仍然是如何快速找到小于某个数字X的最大斐波那契数。 从矩阵开始有一个已知的技巧(称之为M)
1 1
1 0
您可以通过矩阵乘法计算fibbonacci数(第x个数字是M ^ x)。更多细节:https://www.nayuki.io/page/fast-fibonacci-algorithms。最终结果是您可以计算O(logN)矩阵乘法中的数字。
如果它们不适合现有类型,则需要大量计算(乘法和加法)。 同时存储与您第一次计算的2的幂相对应的矩阵,因为您将再次需要它们来获得结果。
总的来说,这应该是O((logN)^ 2 * large_number_multiplications / additions))。
答案 1 :(得分:2)
首先我想告诉你我真的很喜欢这个问题,我不知道所有正整数都可以表示为一组Fibonacci数的总和而不重复,我通过归纳看到了证明它太棒了
为了回答你的问题,我认为我们必须弄清楚如何创建演示文稿。我认为找到这个的简单方法是从我们找到最接近的次要斐波纳契项目的数字。
例如,如果我们想要呈现40:
我们有Fib(9)= 34和Fib(10)= 55所以演示中的第一个元素是Fib(9)
由于40-Fib(9)= 6且(Fib(5)= 5且Fib(6)= 8),下一个元素是Fib(5)。
所以我们有40 = Fib(9)+ Fib(5)+ Fib(2)
请允许我用C#
class Program
{
static void Main(string[] args)
{
List<int> fibPresentation = new List<int>();
int numberToPresent = Convert.ToInt32(Console.ReadLine());
while (numberToPresent > 0)
{
int k =1;
while (CalculateFib(k) <= numberToPresent)
{
k++;
}
numberToPresent = numberToPresent - CalculateFib(k-1);
fibPresentation.Add(k-1);
}
}
static int CalculateFib(int n)
{
if (n == 1)
return 1;
int a = 0;
int b = 1;
// In N steps compute Fibonacci sequence iteratively.
for (int i = 0; i < n; i++)
{
int temp = a;
a = b;
b = temp + b;
}
return a;
}
}
您的结果将在fibPresentation
中答案 2 :(得分:2)
此编码更准确地称为“Zeckendorf表示”:请参阅https://en.wikipedia.org/wiki/Fibonacci_coding
贪婪的方法有效(参见https://en.wikipedia.org/wiki/Zeckendorf%27s_theorem),这里有一些将数字转换为此表示的Python代码。它使用前100个斐波纳契数,并且对所有输入都能正常工作,最高可达927372692193078999175(并且对于任何较大的输入都不正确)。
fibs = [0, 1]
for _ in xrange(100):
fibs.append(fibs[-2] + fibs[-1])
def zeck(n):
i = len(fibs) - 1
r = 0
while n:
if fibs[i] <= n:
r |= 1 << (i - 2)
n -= fibs[i]
i -= 1
return r
print bin(zeck(17))
输出结果为:
0b100101
答案 3 :(得分:1)
由于贪婪的方法似乎有效,因此能够反转关系N=Fn
就足够了。
通过Binet公式Fn=[φ^n/√5]
,其中括号表示最接近的整数。然后使用n=floor(lnφ(√5N))
,您非常接近解决方案。
17 => n = floor(7.5599...) => F7 = 13
4 => n = floor(4.5531) => F4 = 3
1 => n = floor(1.6722) => F1 = 1
(我不排除某些n
值可以被一个人关闭。)
答案 4 :(得分:0)
我不确定这对你来说是否足够有效,但你可以简单地使用Backtracking找到一个(有效的)表示。
如果违反连续或仅一次约束,我会尝试通过获取最大可能的fib数来启动回溯步骤,并且只切换到较小的步数。< / p>