老汉也即将面临找工作的抉择,为了不让自己死相太难看,现在打算刷刷题。都是比较粗浅,大神轻拍!
斐波那契定义
比萨的列奥纳多,又称斐波那契(Leonardo Pisano ,Fibonacci, Leonardo Bigollo,1175年-1250年),意大利数学家,西方第一个研究斐波那契数,并将现代书写数和乘数的位值表示法系统引入欧洲。
斐波那契数列,又称黄金分割数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21、……在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)
(这是老汉从百度上抄过来的,呵呵)
兔子问题
定义
经过月数
|
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
幼仔对数
|
1
|
0
|
1
|
1
|
2
|
3
|
5
|
8
|
13
|
21
|
34
|
55
|
89
|
成兔对数
|
0
|
1
|
1
|
2
|
3
|
5
|
8
|
13
|
21
|
34
|
55
|
89
|
144
|
总体对数
|
1
|
1
|
2
|
3
|
5
|
8
|
13
|
21
|
34
|
55
|
89
|
144
|
233
|
可以明显看出,表中数字1,1,2,3,5,8---构成了一个斐波那锲序列
这时候,递推公式也需要灵活更改,F0 = 1, F1 = 1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)
实现
递归
所以,我们得到第一个代码--递归实现#include <stdio.h>
#define MAX 50
long long Fib_recursion(int n)
{
if (n == 0)
return 0;
else if(n == 1)
return 1;
else if(n > 1)
return Fib_recursion(n - 1) + Fib_recursion (n - 2);
else
return -1;
}
int main(int argc, char *argv[])
{
int n;
long long result;
while(scanf("%d", &n) != EOF)
{
result = Fib_recursion(n);
printf("Done.After %d months, there are %lld pairs of rabbits!\n", n, result);
}
return 0;
}
现在我们对效率进行测试:
$ TIMEFORMAT="" time ./main
50
如上所示,我们采用命令time进行测试,在linux上使用TIMEFORMAT变量来重置默认的posix时间输出格式。得到如下结果:
Done.After 50 months, there are 20365011074 pairs of rabbits!
120.78user 0.00system 2:03.16elapsed 98%CPU (0avgtext+0avgdata 448maxresident)k
0inputs+0outputs (0major+153minor)pagefaults 0swaps
可以看出,当n=50时,这个程序需要占用98%的CPU,耗时两分钟才能跑完。效率太低了
复杂度分析
效率太慢,除了最后一个数,每个数都被算了一遍又一遍,时间复杂度差不多是5n^2/3
复杂度,引自 啊汉的博客
数组
现在我们采用数组实现斐波那契数列,代码如下#include <stdio.h>
#define MAX 100
long long Fib_array(int n)
{
long long a[MAX], result;
int i;
a[0] = 1;
a[1] = 1;
if(n < 2)
{
return -1;
}
for(i = 2; i <= n; i++)
{
a[i] = a[i - 1] + a[i - 2];
}
result = a[n];
return result;
}
int main(int argc, char argv[])
{
int n;
long long result;
scanf("%d", &n);
result = Fib_array(n);
printf("Done.After %d months, there are %lld pairs of rabbits!\n", n, result);
return 0;
}
再次测试
$ TIMEFORMAT="" time ./main
50
瞬间,结果就出来了
Done.After 99 months, there are 3736710778780434371 pairs of rabbits!
0.00user 0.00system 0:01.71elapsed 0%CPU (0avgtext+0avgdata 452maxresident)k
0inputs+0outputs (0major+153minor)pagefaults 0swaps
可以看出,CPU占用率为0,时间为毫秒级复杂度分析
空间复杂度和时间复杂度都是0(n),效率一般,比递归来得快。
复杂度,引自 啊汉的博客迭代
#include <stdio.h>
long long Fib_iteration(int n)
{
long long result, pre_result, temp;
result = pre_result = 1;
while(n >= 2)
{
temp = result;
result += pre_result;
pre_result = temp;
n--;
}
return result;
}
int main(int argc, char argv[])
{
int n;
long long result;
scanf("%d", &n);
result = Fib_iteration(n);
printf("Done.After %d months, there are %lld pairs of rabbits!\n", n, result);
return 0;
}
复杂度分析
时间复杂度是o(n),空间复杂度是o(1)。效率最高。
复杂度,引自 啊汉的博客一只小蜜蜂
好了,说了半天了,还没进入正题。有关斐波那契问题,以后有机会再探讨。先进入HDOJ 2044题,看题
问题
点击打开2044
解题分析
看两个示例,来理解题目的意思
- a = 1 ,b = 2;有一种走法,1->2
- a = 1 , b = 3; 有两种走法, 1-2,1-3
- a = 1 , b = 4; 有三种走法,1-2-4, 1-3-4, 1-2-3-4
- a = 1, b = 5; 有五种走法 ,1-3-5,1-2-4-5,1-3-4-5,1-2-3-5,1-2-3-4-5
从上面的这几个例子中,可以发现这么个规律,前两次走法的和就是这一次的走法。老汉可以猜测这是个斐波那契数列;既然是斐波那契数列,那么如何确定n的值呢?
n = b - a?
看看这样行不行啊,
- a = 1 ,b = 2; n = 1; f(1) = 1;
- a = 1 , b = 3; n = 2; f(2) = 2;
- a = 1 , b = 4; n = 3; f(3) = 3 = f(1) + f(2)
- a = 1, b = 5; n =4; f(4) = 5 = f(2) + f(3)
还真可以,行了,这就是个斐波那契数列了。有兴趣自己推一推
代码
#include <stdio.h>
#define MAX 50
int main()
{
/* gcc编译器,支持long long型变量 */
long long fib[MAX];//windows编译器请写为__int64
/* N为实例数量;a,b为两个蜂房编号;i,j作为循环变量*/
int N, a, b, i, j;
/*len 用来保存两个蜂房的距离,作为斐波那锲数列的参数*/
int len;
while (scanf("%d", &N) != EOF)
{
for(i = 0; i < N; i++)
{
scanf("%d %d", &a, &b);
len = b - a;
/*检查输入的正确性,如果a>b,报错*/
if(a > b)
{
printf("error: Wrong Data Format!\n");
break;
}
fib[1] = 1;
fib[2] = 2;
for(j = 3; j <= len; j++)
{
fib[j] = fib[j-1] + fib[j-2];
}
printf("%lld\n", fib[b-a]);
}
}
return 0;
}
同类问题
HDOJ 2041 超级楼梯
题目
分析
一画图,一看规律,一次加一或者加二,马上发现是一个典型的二阶Fibonacci(斐波那契)数列递增规律:
每加一格楼梯就会增加两条新路线,一条连向前一格,一条连向前两格,即递增规律Fib[i]=Fib[i-1]+Fib[i-2];
代码
#include <stdio.h>
int main(int argc, char *argv[])
{
int n, m;
/*windows环境下请替换为__int64型*/
long long result, pre_result, temp;
scanf("%d", &n);
while(n--)
{
scanf("%d", &m);
result = pre_result = 1;
while(m > 2)
{
temp = result;
result += pre_result;
pre_result = temp;
m--;
}
/*windows环境下请替换为%I64d*/
printf("%lld\n", result);
}
return 0;
}