以下是Problem 25 - Project Euler的实现(请参阅代码中的注释以了解其工作原理):
#include <iostream> //Declare headers and use correct namespace
#include <math.h>
using namespace std;
//Variables for the equation F_n(newTerm) = F_n-1(prevTerm) + Fn_2(currentTerm)
unsigned long long newTerm = 0;
unsigned long long prevTerm = 1; //F_1 initially = 1
unsigned long long currentTerm = 1; //F_2 initially = 2
unsigned long long termNo = 2; //Current number for the term
void getNextTerms() { //Iterates through the Fib sequence, by changing the global variables.
newTerm = prevTerm + currentTerm; //First run: newTerm = 2
unsigned long long temp = currentTerm; //temp = 1
currentTerm = newTerm; //currentTerm = 2
prevTerm = temp; //prevTerm = 1
termNo++; //termNo = 3
}
unsigned long long getLength(unsigned long long number) //Returns the length of the number
{
unsigned long long length = 0;
while (number >= 1) {
number = number / 10;
length++;
}
return length;
}
int main (int argc, const char * argv[])
{
while (true) {
getNextTerms(); //Gets next term in the Fib sequence
if (getLength(currentTerm) < 1000) { //Checks if the next terms size is less than the desired length
}
else { //Otherwise if it is perfect print out the term.
cout << termNo;
break;
}
}
}
这适用于该示例,并且只要这一行就会快速运行:
if (getLength(currentTerm) < 1000) { //Checks if the next term's size is less than the desired length
表示20或更低而不是1000.但是如果这个数字大于20就需要一个永远,我的耐心越来越好,我停止了程序,我怎样才能使这个算法更有效率?
如果您有任何问题,请在评论中提问。
答案 0 :(得分:4)
Fibonachi数字(以及任何线性递归序列)都有一个封闭的公式。
所以F_n = C1 * a^n + C2 * b^n
,其中C1,C2,a和b是可以从初始条件中找到的数字,即来自
F_n + 2 = F_n + 1 + F_n
F_1 = 1
F_2 = 1
我不是故意在这里给出他们的价值观。这只是一个暗示。
答案 1 :(得分:3)
nth fibonacci number = =
(g1^n-g2^n)/sqrt(5).
where g1 = (1+sqrt(5))/2 = 1.61803399
g2 = (1-sqrt(5))/2 = -0.61803399
为了找到第n个斐波那契数的长度,我们可以计算log(第n个斐波纳契数)。那么,第n个斐波纳契数的长度是,
log((g1^n-g2^n)/sqrt(5)) = log(g1^n-g2^n)-0.5*log(5).
you can just ignore g2^n, since it is very small negative number.
因此,第n个斐波那契的长度是
n*log(g1)-0.5*log(5)
我们需要找到'n'的最小值,使得这个长度= 1000,所以我们可以找到长度大于999的n的值。
所以,
n*log(g1)-0.5*log(5) > 999
n*log(g1) > 999+0.5*log(5)
n > (999+0.5*log(5))/log(g1)
n > (999.3494850021680094)/(0.20898764058551)
n > 4781.859263075
因此,所需的最小n是4782.不使用任何编码,最简单的方法。
注意:在基数10中使用了所有日志。
答案 2 :(得分:1)
这可能会加快它的速度:
int getLength(unsigned long long number) //Returns the length of the number when expressed in base-10
{
return (int)log10(number) + 1;
}
...但是,使用unsigned long long
无法达到1000位数。我建议研究任意精度的算术库,或内置任意精度算术的语言。
答案 3 :(得分:0)
您可以尝试使用矩阵求幂来计算斐波纳契数。然后重复加倍以获得具有超过1000个数字的数字并在该范围内使用二分搜索来找到第一个。
答案 4 :(得分:0)
使用双打,你可以知道最高指数是308:
得到250的exp序列,然后将你的两个数字除以1e250。使用这两个数字重新启动算法
如果你这样做4次,你会得到正确的答案
答案 5 :(得分:0)
C ++代码可能如下:
#include "iostream"
#include "string.h"
#include "algorithm"
using namespace std;
string addTwoString(string a, string b)
{
if (a.length() == 0)
{
return b;
}
if (b.length() == 0)
{
return a;
}
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
string result = "";
string str_1, str_2;
if (a.length() > b.length())
{
str_1 = b;
str_2 = a;
}
else
{
str_1 = a;
str_2 = b;
}
int index = 0;
int value = 0, over_value = 0;
for (; index < str_1.length(); ++index)
{
int temp_1 = (int)(str_1[index] - '0');
int temp_2 = (int)(str_2[index] - '0');
int temp = temp_1 + temp_2 + over_value;
value = temp % 10;
over_value = temp / 10;
char c = (char)(value + '0');
result += c;
}
for (; index < str_2.length(); ++index)
{
int temp_2 = (int)(str_2[index] - '0');
int temp = temp_2 + over_value;
value = temp % 10;
over_value = temp / 10;
char c = (char)(value + '0');
result += c;
}
if (over_value > 0)
{
char c = (char)(over_value + '0');
result += c;
}
reverse(result.begin(), result.end());
return result;
}
int main()
{
string a = "1";
string b = "1";
string c = addTwoString(a, b);
int index = 3;
while (c.length() < 1000)
{
a = b;
b = c;
c = addTwoString(a, b);
++ index;
}
cout << index << endl;
}
答案 6 :(得分:0)
我刚刚使用了一个递归函数,它可以垂直添加数组来完成问题。基本上零运行时间,少于50行代码。享受:
#include <stdio.h>
int Calc_Fib (int numA[], int numB[], int temp[], int index) {
int i = 0;
//Check 1000th digit for non-zero value.
if (numB[999] != 0) return index;
//Add arrays A and B vertically.
for (i = 0; i < 1000; ++i) {
temp[i] += (numA[i] + numB[i]);
if (temp[i] > 9) {
temp[i + 1] = temp[i] / 10;
temp[i] %= 10;
}
numA[i] = numB[i];
numB[i] = temp[i];
temp[i] = 0;
}
Calc_Fib(numA, numB, temp, ++index);
}
int main() {
int numA[1000]; //Holds previous term.
int numB[1000]; //Holds current term.
int temp[1000]; //Holds temporary number for vertical addition.
int i = 0;
int indexVal = 2;
for (i = 0; i < 1000; ++i) {
numA[i] = 0;
numB[i] = 0;
temp[i] = 0;
}
//Initialize first two terms.
numA[0] = (numB[0] = 1);
indexVal = Calc_Fib(numA, numB, temp, indexVal);
printf("Tada: %d\n", indexVal);
return 0;
}