首页 > 代码库 > 斐波那契 [ Fibonacci] 数列之大整数求和
斐波那契 [ Fibonacci] 数列之大整数求和
之前做到一题, 不过由于Honor Code的缘故就不说是啥了, 很多人都知道 (-_-)
大概是说有n个牌,每个牌只有A,B两种状态. 当出现连续3个牌的状态一样时,认为不完美.
给出一个[1, 10000]的整数, 让求出完美的排列个数
那么我们就可以分析一下:
/*-------------------------------------------------------------------------------
分析:
首先要求出不美观的个数,但是尝试可以发现美观的排列更容易分析
而总的排列个数为 2^n 故而求出n个骨牌美观的排列数,设为F(n)
进而让 2^n - F(n) 的结果就是所求.
那么我们探索F(n)的方程
假设已经有骨牌排列 [][n-1][n-2][n-3]...
前 n-1 块排列已经是美观的,那么分析第 n 块骨牌的情况
若 [n-1][n-2] 的颜色一样,需美观那么 第n块的颜色被注定
而[n-1][n-2]的颜色一样,必然[n-3]的颜色和这2块不一样
这就说明,第[n-3]块,或者说前 n-3 块牌的排列决定了第n块的排列
若[n-1][n-2]的颜色不一样,已知前 n-1已经是美观的排列
那么F(n-1) = [n-1][n-2] 颜色一样 + 颜色不一样2种情况
那么第n-1, n-2块牌不一样的 个数 就等于 F(n-1) - F(n-3)
由于第n-1, n-2块牌子颜色不同,故而第 n块牌是有2种方法的
综上所述,F(n) = F(n-1) + F(n-1) - F(n-3) = 2F(n-1) - F(n-3)
有斐波那契数列 U(n) = U(n-1) + U(n-2)
又有 U(n-1) = U(n-2) + U(n-3) 故而 U(n-2) = U(n-1) - U(n-3)
代入原式就有 U(n) = 2U(n-1) - U(n-3) 和F(n) 同
故而F(n)和斐波那契数列递推式等同
有 F(n) = F(n-1) + F(n-2)
那么, 最终的结果就是 2^n - F(n) 了! // 需完成1次大整数加法和1次大整数减法
我代码里的减法是阉割版本的..因为2^n - F(n)必然 > 0, 所以没考虑负数的问题.
在这里是足够用了...
-------------------------------------------------------------------------------*/
1 // 假设美观个数为F(n),F(n) = F(n-1)+F(n-2) 2 // F(1) = 2, F(2) = 4, F(3) = 6 3 #include<iostream> 4 #include<cstring> 5 using namespace std; 6 // Function Add(char* addA,char* addB,char* Result) 7 // Result = addA + addB ,返回 Result 8 void Add(char* addA,char* addB,char* Result){ 9 int curIndexA,curIndexB,carry; // 2个加数计算的当前下标,进位 10 int tempSum,resultIndex,longerLength; 11 int valueA,valueB; 12 13 char *tempResult = new char[5000]; 14 15 int lengthA = strlen(addA); 16 int lengthB = strlen(addB); 17 longerLength = lengthA > lengthB ? lengthA+2 : lengthB+2; 18 tempResult = new char[longerLength * sizeof(char)]; 19 20 curIndexA = lengthA - 1; // 从个位数开始计算 即 length-1 21 curIndexB = lengthB - 1; 22 23 carry = 0; 24 resultIndex = 0; 25 tempSum = 0; 26 27 while (curIndexA >= 0 || curIndexB >= 0){ 28 valueA = curIndexA < 0 ? ‘0‘ : addA[curIndexA]; // 真正进行运算的 valueA,valueB 29 valueB = curIndexB < 0 ? ‘0‘ : addB[curIndexB]; 30 31 tempSum = valueA + valueB - 2*‘0‘; 32 if(carry) tempSum = tempSum + 1; 33 34 if(tempSum > 9){ 35 carry = 1; 36 tempSum = tempSum % 10; 37 } 38 else carry = 0; 39 40 tempResult[resultIndex] = tempSum + ‘0‘; 41 resultIndex++; 42 curIndexA--; 43 curIndexB--; 44 } 45 46 if(carry)tempResult[resultIndex++] = ‘1‘; 47 tempResult[resultIndex] = ‘\0‘; 48 49 int i = 0; 50 for(resultIndex = resultIndex-1; resultIndex >= 0; ++i,--resultIndex){ 51 Result[i] = tempResult[resultIndex]; 52 } 53 Result[i] = ‘\0‘; 54 55 delete []tempResult; 56 } 57 58 // Function void Sub(char subA[],char subB[]){ 59 // subA = subA - subB, 返回 subA 60 // 留意比如 1 - 9, 得到负数,没关系,最后取值是 (1-9)+10 = 2 61 // 注意借位设置 = true, 当借位 = true, 进行计算的value要-1,自行手工模拟即知 62 void Sub(char subA[],char subB[]){ 63 int lengthB = strlen(subB); 64 int lengthA = strlen(subA); 65 int valueA,valueB,theirSub; 66 67 int curIndexB = lengthB-1; 68 int curIndexA = lengthA-1; 69 bool borrow = false; 70 71 for(; curIndexA >= 0; --curIndexA,--curIndexB){ 72 73 valueA = (borrow == false) ? subA[curIndexA] - ‘0‘ : subA[curIndexA]-1 -‘0‘; 74 valueB = curIndexB < 0 ? 0 : subB[curIndexB] - ‘0‘; 75 theirSub = valueA - valueB; 76 if(theirSub >= 0){ 77 borrow = false; 78 subA[curIndexA] = theirSub + ‘0‘; 79 } 80 else{ 81 borrow = true; 82 subA[curIndexA] = 10 + theirSub + ‘0‘; 83 } 84 } 85 } 86 87 void DisplayCharArray(char *Array){ 88 for(int i = 0; i < strlen(Array); ++i){ 89 cout<< Array[i]; 90 } 91 } 92 int main(){ 93 94 char *prenum = new char[5000]; 95 char *middle = new char[5000]; 96 char *perfectMethod = new char[5000]; 97 char *ArrayTempPoint = NULL; 98 char *allMethod = new char[5000]; // 2^n 99 prenum[0] = ‘2‘; 100 prenum[1] = ‘\0‘; // 记得设置 ‘\0‘ 边界 101 middle[0] = ‘4‘; 102 middle[1] = ‘\0‘; 103 104 int num; 105 cin>> num; 106 107 for(int i = 2; i < num; ++i){ // 关键算法,计算完美数 108 Add(prenum,middle,perfectMethod); 109 ArrayTempPoint = prenum; 110 prenum = middle; 111 middle = perfectMethod; 112 if(i != num-1) perfectMethod = ArrayTempPoint; 113 } 114 115 delete []ArrayTempPoint; 116 delete []prenum; 117 // TEST Perfect Num 118 //cout<< "Perfect Num : "<<endl; DisplayCharArray(perfectMethod); cout<<endl; 119 120 char *add1 = new char[5000]; 121 add1[0] = ‘2‘; 122 add1[1] = ‘\0‘; 123 124 125 for( int i = 1; i < num ; ++i){ // 利用加法实现求 2^n 126 Add(add1,add1,allMethod); 127 ArrayTempPoint = add1; 128 add1 = allMethod; 129 if(i != num-1){ 130 allMethod = ArrayTempPoint; 131 } 132 } 133 delete []ArrayTempPoint; // ArrayTempPoint,add1 134 135 // TEST 2^n 136 //cout<< "2^n : "<<endl; DisplayCharArray(allMethod); cout<<endl; 137 138 139 Sub(allMethod,perfectMethod); // 进行相减 140 bool start = false; 141 for(int i = 0; i < strlen(allMethod); ++i){ 142 if(allMethod[i] != ‘0‘) start = true; 143 if(start == true && allMethod[i] != ‘\0‘) cout<< allMethod[i]; 144 } // 注意为何我要这样输出 ? 145 146 delete []perfectMethod; // 内存清理 147 delete []allMethod; 148 149 return 0; 150 151 } 152 153 154 155 /********************************************************************* 156 对于指针一定要细心 因为你几乎是什么都可以修改 157 比如 char *pChar = new char[100]; 158 那么系统默认 pChar[0] = ‘\0‘ 你如果这时候擅自修改 pChar[0] 159 会使得这个数组丢失 ‘\0‘ 160 *********************************************************************/
斐波那契 [ Fibonacci] 数列之大整数求和