首页 > 代码库 > 斐波那契 [ 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 *********************************************************************/
View Code

 

  

斐波那契 [ Fibonacci] 数列之大整数求和