台阶问题
2013-08-20 16:41
211 查看
有一个100个台阶的阶梯,一次可以选择上一个台阶,或者两个台阶,最后上到楼梯顶有几种走法?
很明显的递归方程:f(n)=f(n-1)+f(n-2),f(1)=1,f(2)=2.求f(100).
即使是用 __int64 来存储,也会产生溢出,所以写了如上的不会溢出的程序。下面的程序在第92个数的时候产生溢出:
输出为:
注:__int8、__int16、__int32、__int64 分别是定义8位、16位、32位、64位有符号整数的关键字,其表示范围分别是-128~127、-65536~65535、-2147483648~2147483647、-9223372036854775808~9223372036854775807,其数量级分别是10^2(百)、10^4(万)、10^9(十亿)、10^18(百亿亿)。
正确结果573147844013817084101达到了10^20数量级。所以产生了溢出。
网上有一个O(logn)的时间算法。其来源于这样一个公式,设数学函数f(n)表示第n个fibonacci数,即f(1)=1, f(2)=1, f(3)=2,f(4)=3……然后求第n个fibonacci数转化为求矩阵{1,1;1,0}的n-1次方(左上角元素即为结果)。求次方可以使用折半的方法求出来。
以下是代码:
不过因为是long long int 类型,所以还是在第93个溢出了。
很明显的递归方程:f(n)=f(n-1)+f(n-2),f(1)=1,f(2)=2.求f(100).
/*file: refibnacii.c*/ /* input one number between 1 and 100, print the output of the result */ /* * Sample Input: 100 * Sample Output: 573147844013817084101 */ #include <stdio.h> #include <assert.h> #include <string.h> /*memcpy*/ #include <stdlib.h> /*atoi*/ /* redefine N we can accept any large input */ #define N (100) int main(int argc, char **argv){ int n,i,j; unsigned char t ,a ,b ; unsigned char carry,sum; assert (2==argc); n=atoi (argv[1]); assert (0<n && n<101); if (1==n){ printf ("%d\n",1); return 0; } memset (a,0,N); memset (b,0,N); a[0]=1; b[0]=2; for (i=2; i<n; ++i){ memcpy (t,b,N); carry=0; for (j=0; j<N; j++){ sum = b[j]+a[j]+carry; carry = sum/10; b[j] = sum%10; } memcpy (a,t,N); } for (i=N-1; i>=0; i--){ if (b[i]){ break; } } for (j=i; j>=0; j--){ printf ("%c",b[j] | 0x30); } printf ("\n"); return 0; }
即使是用 __int64 来存储,也会产生溢出,所以写了如上的不会溢出的程序。下面的程序在第92个数的时候产生溢出:
#include "stdio.h" int main(int argc, char* argv[]) { __int64 f1 = 1, f2 = 2, tmp; int i; printf("%d: %I64d\n", 1, f1); printf("%d: %I64d\n", 1, f2); for (i=0; i<98; i++) { tmp = f2 ; f2 = f1 + f2; f1 = tmp; printf("%d: %I64d\n", i+3, f2); } return 0; }
输出为:
1: 1 1: 2 3: 3 4: 5 5: 8 6: 13 7: 21 8: 34 9: 55 10: 89 11: 144 12: 233 13: 377 14: 610 15: 987 16: 1597 17: 2584 18: 4181 19: 6765 20: 10946 21: 17711 22: 28657 23: 46368 24: 75025 25: 121393 26: 196418 27: 317811 28: 514229 29: 832040 30: 1346269 31: 2178309 32: 3524578 33: 5702887 34: 9227465 35: 14930352 36: 24157817 37: 39088169 38: 63245986 39: 102334155 40: 165580141 41: 267914296 42: 433494437 43: 701408733 44: 1134903170 45: 1836311903 46: 2971215073 47: 4807526976 48: 7778742049 49: 12586269025 50: 20365011074 51: 32951280099 52: 53316291173 53: 86267571272 54: 139583862445 55: 225851433717 56: 365435296162 57: 591286729879 58: 956722026041 59: 1548008755920 60: 2504730781961 61: 4052739537881 62: 6557470319842 63: 10610209857723 64: 17167680177565 65: 27777890035288 66: 44945570212853 67: 72723460248141 68: 117669030460994 69: 190392490709135 70: 308061521170129 71: 498454011879264 72: 806515533049393 73: 1304969544928657 74: 2111485077978050 75: 3416454622906707 76: 5527939700884757 77: 8944394323791464 78: 14472334024676221 79: 23416728348467685 80: 37889062373143906 81: 61305790721611591 82: 99194853094755497 83: 160500643816367088 84: 259695496911122585 85: 420196140727489673 86: 679891637638612258 87: 1100087778366101931 88: 1779979416004714189 89: 2880067194370816120 90: 4660046610375530309 91: 7540113804746346429 92: -6246583658587674878 93: 1293530146158671551 94: -4953053512429003327 95: -3659523366270331776 96: -8612576878699335103 97: 6174643828739884737 98: -2437933049959450366 99: 3736710778780434371 100: 1298777728820984005
注:__int8、__int16、__int32、__int64 分别是定义8位、16位、32位、64位有符号整数的关键字,其表示范围分别是-128~127、-65536~65535、-2147483648~2147483647、-9223372036854775808~9223372036854775807,其数量级分别是10^2(百)、10^4(万)、10^9(十亿)、10^18(百亿亿)。
正确结果573147844013817084101达到了10^20数量级。所以产生了溢出。
网上有一个O(logn)的时间算法。其来源于这样一个公式,设数学函数f(n)表示第n个fibonacci数,即f(1)=1, f(2)=1, f(3)=2,f(4)=3……然后求第n个fibonacci数转化为求矩阵{1,1;1,0}的n-1次方(左上角元素即为结果)。求次方可以使用折半的方法求出来。
以下是代码:
/* * szl_fibonacci.c * * copyright @ dnxiaochou@gmail.com * * overflow at the 93th fibonacci number. */ /* time complexity: O(logN) */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * a math formula is used in the following algorithm. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <assert.h> typedef struct _matrix_2x2{ long long int m_00; long long int m_01; long long int m_10; long long int m_11; }Matrix_2x2; /* init fibonacii */ void matrix_init_fibonacci (Matrix_2x2 * m_dest){ m_dest->m_00 = 1; m_dest->m_01 = 1; m_dest->m_10 = 1; m_dest->m_11 = 0; } /* clone */ void matrix_clone (Matrix_2x2 * m_dest, const Matrix_2x2 * m_src){ m_dest->m_00 = m_src->m_00; m_dest->m_01 = m_src->m_01; m_dest->m_10 = m_src->m_10; m_dest->m_11 = m_src->m_11; } /* matrix multiply */ void matrix_mul (Matrix_2x2 * m_dest, const Matrix_2x2 * m_src1, const Matrix_2x2 * m_src2){ m_dest->m_00 = m_src1->m_00 * m_src2->m_00 + m_src1->m_01 * m_src2->m_10; m_dest->m_01 = m_src1->m_00 * m_src2->m_01 + m_src1->m_01 * m_src2->m_11; m_dest->m_10 = m_src1->m_10 * m_src2->m_00 + m_src1->m_11 * m_src2->m_10; m_dest->m_11 = m_src1->m_10 * m_src2->m_01 + m_src1->m_11 * m_src2->m_11; } /* get power of a matrix */ void matrix_power (Matrix_2x2 * m_dest, const Matrix_2x2 * m_src, int n){ Matrix_2x2 m_tmp; assert (0 < n); if (1 == n){ matrix_clone (m_dest, m_src); } else if (1 & n){ matrix_power (&m_tmp, m_src, (n-1)>>1); matrix_mul (m_dest, &m_tmp, &m_tmp); matrix_mul (&m_tmp, m_dest, m_src); matrix_clone (m_dest, &m_tmp); } else{ matrix_power (&m_tmp, m_src, n>>1); matrix_mul (m_dest, &m_tmp, &m_tmp); } } long long int fibonacci (int n){ long long int ret = 1; Matrix_2x2 mat_fib_1, mat_fib_dec_n; matrix_init_fibonacci (&mat_fib_1); matrix_clone (&mat_fib_dec_n, &mat_fib_1); if (1 < n){ matrix_power (&mat_fib_dec_n, &mat_fib_1, n-1); } return mat_fib_dec_n.m_00; } int main (int argc, char * * argv){ int n,i; long long int f; scanf ("%d", &n); for (i=1; i<n; i++){ f = fibonacci (i); printf ("%d\t%lld\n", i, f); } return 0; }
不过因为是long long int 类型,所以还是在第93个溢出了。