斐波那契 [ 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] 數列之大整數求和