关于 斐波那契据数列 的引申
最基本的函数模型是:
/ 0 n=0
f(n)= 1 n=1
\ f(n-1)+(f-2) n>1
我们一般的解法是:
int fun( int n )
{
if ( 0 == n )
{
return0;
}
elseif ( 1 == n )
{
return1;
}
else
{
returnfun(n - 1) + fun(n - 2);
}
}
但是递归在大的数据的情况下可能超时( 特别是在OJ上的时候 )
那么我们想想还可以用:
#include <stdio.h>
int main()
{
long long f[51] = { 0, 1 };
long long n, a0 = 0, a1 = 1;
int i;
for( i = 2; i <= 50 ; i++ )
{
f[i] = a0 + a1; // 此处只要遍历一次就ok
a0 = a1;
a1 = f[i];
}
while( scanf("%d", &n) != EOF ) // 我们可以得到任意的n的 Fibonacci 结果
{
printf("%lld\n", f[n]);
}
return 0;
}
此处还要介绍一个非常好的办法:利用矩阵( 在刷oj的时候想到的 )
Fibonacci 说白了就是一个递推序列,f( n ) = f( n - 1 ) + f( n - 2 );
变形一下有: f( n ) = 1 *f( n - 1 ) + 1 * f( n - 2 );
那么使用矩阵表示就是:( 注意:下面表示的不好看,其实是矩阵表示,见谅! )
| f( n ) | | 1 1 | | f( n-1 ) |
| f( n-1 ) | = | 1 0 | * | f( n-2 ) |
即:
| f( n ) | | 1 1 | | f( 1 ) |
| f( n-1 ) | = | 1 0 | ^( n-1 ) * | f( 0 ) |
就是那个| 1 1 |
| 1 0 | 的n-1次方后 乘以 初始化的两个数就是!
#include <stdio.h>
long long all[71];
void fun( int n )
{
int i;
long long mat[2][2] = { 1, 0, 0, 1 }; // 单位矩阵
long long tmp[2][2];
for( i = 2; i <= n; i++ )
{
tmp[0][0] = mat[0][0];
tmp[0][1] = mat[0][1];
tmp[1][0] = mat[1][0];
tmp[1][1] = mat[1][1];
mat[0][0] = tmp[0][0] + tmp[0][1];
mat[0][1] = tmp[0][0];
mat[1][0] = tmp[1][0] + tmp[1][1];
mat[1][1] = tmp[1][0];
all[i] = mat[0][0] * all[1] +mat[0][1] * all[0];
}
}
int main()
{
int n;
all[0] = 0;
all[1] = 1;
fun( 70 );
while( scanf("%d", &n) != EOF)
{
if( n == 0 )
{
printf("0\n");
}
else if( n == 1 )
{
printf("1\n");
}
else
{
printf("%lld\n",all[n]);
}
}
return 0;
}关于 Fibonacci 的变体:
1》青蛙跳台阶问题:
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
分析:
当n =1, 只有1中跳法;当n =2时,有2种跳法;当n = 3 时,有3种跳法;当n = 4时,有5种跳法;当n = 5时,有8种跳法
所以还是Fibonacci 序列,只不过初始化为:f(1) = 1; f(2) = 2;
#include <stdio.h>
long long all[71];
void fun( int n )
{
int i;
long long mat[2][2] = { 1, 0, 0, 1 }; // 单位矩阵
long long tmp[2][2];
for( i = 3; i <= n; i++ )
{
tmp[0][0] = mat[0][0];
tmp[0][1] = mat[0][1];
tmp[1][0] = mat[1][0];
tmp[1][1] = mat[1][1];
mat[0][0] = tmp[0][0] + tmp[0][1];
mat[0][1] = tmp[0][0];
mat[1][0] = tmp[1][0] + tmp[1][1];
mat[1][1] = tmp[1][0];
all[i] = mat[0][0] * all[2] +mat[0][1] * all[1];
}
}
int main()
{
int n;
all[0] = 0;
all[1] = 1;
all[2] = 2;
fun( 70 );
while( scanf("%d", &n) != EOF)
{
if( n == 0 || n == 1 )
{
printf("1\n");
}
else
{
printf("%lld\n",all[n]);
}
}
return 0;
}
或者代码为:
( 下面的代码计算大的数的时候可能超时,不建议 )
#include <stdio.h>
int count;
void fun( int s, int i, int n )
{
s += i;
if( s == n )
{
count++;
return;
}
else if( s > n )
{
return;
}
else // 此处分叉
{
fun( s, 1, n );
fun( s, 2, n );
}
}
int main()
{
int n;
while( scanf("%d", &n) != EOF)
{
count = 0;
fun( 0, 0, n );
printf("%d\n", count);
}
return 0;
}
2》 跳台阶问题(变态跳台阶)
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法
分析:
/ 1 n=1
f(n)= 2 n=2
\ f(n-1)+(f-2) n>2
#include <stdio.h>
int main()
{
long long f[51] = { 0, 1, 2 };
long long n = 3, sum = 3;
int i;
for( i = 3; i <= 50 ; i++ )
{
f[i] = sum + 1;
sum += f[i];
}
while( scanf("%d", &n) != EOF )
{
printf("%lld\n", f[n]);
}
return 0;
}
3》 矩形覆盖
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
分析:
同上!( 说到底还是其变形 )
#include <iostream>
using namespace std;
int main()
{
long long f[71];
int i;
int n;
f[0] = 1;
f[1] = 1;
for( i = 2; i <= 70; i++ )
{
f[i] = f[i-1] + f[i-2];
}
while( cin >> n )
{
cout << f[n] << endl;
}
return 0;
}