遞迴分治-大整數乘法
最近在學演算法,想著不能只是學,要深刻領悟,需要記錄,需要寫程式碼,需要分析……所以就誕生了這篇部落格。
問題描述:
設X和Y都是n位整數,計算它們的乘積XY。可以使用傳統的數學計算方法,但是這樣做計算步驟太多,效率較低。如果將每個一位數的乘法或加法看做一步運算,則這種方法需要進行O(n^2)步運算才能求出乘積XY。
方法一
基本計算步驟如下,如:56*78
第一步:6*8;
第二步:5*8;
第三步:6*7;
第四步:5*7;
第五步:以上4步的和加起來,得到最後的結果。
將以上的例子進行抽象,即可以這樣表示:
將n位十進位制(還包括其他進位制,如二進位制、八進位制、十六進位制等)整數X和Y都分為2段,每段的長為n/2位。即:
這樣XY的乘積就是
由以上的等式我們可以看出,需要4次乘法,分別是:AC,AD,BC,BD,以及3次加法,還有3次移位操作。所有這些加法和移位公用O(n)步運算。設T(n)是2個n位整數相乘所需的運算總數,則有:
T(n) =
然後,我們進行計算,得到該演算法的時間複雜度為O(n^2),具體過程如下:
實現程式碼如下:
#include<stdio.h>
#include<math.h>
#define MAX_LENGTH 10
void sqperateNum(int num, int seArray_num[]); //資料儲存到陣列中
int main()
{
int i=0, j=0;
int num1, num2;
int sum = 0;
int seArray_num1[MAX_LENGTH] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; //初始化陣列
int seArray_num2[MAX_LENGTH] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
printf("Please input two numbers:\n");
scanf("%d%d", &num1, &num2);
sqperateNum(num1, seArray_num1);
sqperateNum(num2, seArray_num2);
while (seArray_num1[i]!=-1)
{
while (seArray_num2[j] != -1)
{
sum += seArray_num1[i] * seArray_num2[j] * pow(10.0, (i + j));
j++;
}
i++;
j = 0;
}
printf("%d*%d=%d\n", num1, num2, sum);
return 0;
}
//資料儲存到陣列中
void sqperateNum(int num, int seArray_num[])
{
int k = 0;
do
{
seArray_num[k] = num % 10;
num /= 10;
k++;
} while (num%10!=0 ||(num/10 !=0));
}
方法二
然後我們對於該問題進行優化,要想改進該演算法的複雜性,必須減少乘法的次數。我們對以上的表示式進行一個優化,得到如下的表示式:
通過以上表達式變形,我們只需進行3次n/2位整數的乘法,6次加減法操作和2次移位。由此可得如下的表示式:
T(n) =
再次進行計算,得到該演算法的時間複雜度為O
程式碼如下,這個程式碼是在別人的基礎上改了一下,具體如下:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int IntegerMultiply(int X, int Y, int N)
{
int x = X;
int y = Y;
if ((0 == x) || (0 == y))
return 0;
if (1 == N)
{
return x*y;
}
else
{
int XL = x / (int)pow(10., (int)N / 2);
int XR = x - XL * (int)pow(10., N / 2);
int YL = y / (int)pow(10., (int)N / 2);
int YR = y - YL * (int)pow(10., N / 2);
int XLYL = IntegerMultiply(XL, YL, N / 2);
int XRYR = IntegerMultiply(XR, YR, N / 2);
int XLYRXRYL = IntegerMultiply(XL - XR, YR - YL, N / 2) + XLYL + XRYR;
return (XLYL * (int)pow(10., N) + XLYRXRYL * (int)pow(10., N / 2) + XRYR);
}
}
int main()
{
int x = 1234, y = 9876;
int value = 0;
value = IntegerMultiply(x, y, 4);
printf("%ld*%ld=%ld", x,y,value);
return 0;
}
綜上所述,主要是掌握對演算法複雜度的推導,以及實現相應的演算法。在這裡,不得不感嘆數學家的厲害,只是一個小小的公式變換,就將複雜度大大降低了。請大數學家們收下我的膝蓋,哈哈~
相關推薦
遞迴分治-大整數乘法
最近在學演算法,想著不能只是學,要深刻領悟,需要記錄,需要寫程式碼,需要分析……所以就誕生了這篇部落格。 問題描述: 設X和Y都是n位整數,計算它們的乘積XY。可以使用傳統的數學計算方法,但是這樣做計算步驟太多,效率較低。如果將每個一位數的乘法或加法看做
分治-大整數乘法
請設計一個有效的演算法,可以進行兩個n位大整數的乘法運算 小學的方法:O(n2) 效率太低 X= Y= X = a 2n/2+ b Y = c 2n/2+ d XY
分治演算法解決大整數乘法問題
整數相乘:小整數相乘在演算法時間分析中可以認為是常數時間,但是對於大整數,時間需要考慮。兩個N位數的整數X和Y相乘,常規方法花費時間是,因為X的每一位都要和Y的每一位相乘,是兩層迴圈。 分治演算法解決整數相乘問題: 例如,X是12345678,Y是87654321,將X和Y都拆成兩半,得到
大整數乘法中的分治思想(TOOM-COOK的一種使用方法)
演算法分析與設計學習中,接觸到一道大整數乘法問題,分享出來,原題目如下: 演算法分析在用分治法求兩個n位大整數u和v的乘積時,將u和v都分割為長度為n/3的3段。證明可以用5次n/3位整數的乘法求得uv的值。按此思想設計大整數乘積的分治方法,並分析演算法的計算
【分治演算法】大整數乘法
大整數的乘法 在計算機中,長整形(long int)變數的範圍不能超過10位數。即便用雙精度(double)變數,也僅能保證16位有效數字 的精度。在某些需要更高精度的乘法運算場合,需要
2980 大整數乘法
沒有 程序代碼 pre != return 註意 string str1 改變 題目來源:http://bailian.openjudge.cn/practice/2980/描述求兩個不超過200位的非負整數的積。輸入有兩行,每行是一個不超過200位的非負整數,沒有多余的前
light oj 1024 - Eid 大整數乘法
imp borde mean ron [] public ans test case cas In a strange planet there are n races. They are completely different as well as their food
Multiply Strings大整數乘法
height image 分析 特殊情況 pac 什麽 .com 總結 pos [抄題]: 以字符串的形式給定兩個非負整數 num1 和 num2,返回 num1 和 num2 的乘積。 [暴力解法]: 時間分析: 空間分析: [思維問題]: 還要找到結果中第一位不等於
caioj1450:【快速傅裏葉變換】大整數乘法
rose clas scan name 代碼 printf 答案 r+ 傅裏葉變換 【傳送門:caioj1450】 簡要題意: 給出兩個超級大的整數,求出a*b 題解: Rose_max出的一道FFT例題,卡掉高精度 = = 只要把a和b的每一
大整數乘法
space ret algorithm 進行 cout while 當前 ostream cstring #include<cmath> #include<cstdio> #include<cstring> #include&l
關於大整數乘法和加法的一些整理
例如,有兩個大整數,a和b,其中a、b位數都是大於10的。我們知道,在做OJ的題時,碰到大整數的乘法,不能直接用a*b得到結果,那樣是不對的,所以需要用陣列來儲存。 首先,很簡單,定義兩個陣列(足夠長),s1和s2,分別用來儲存大整數a和b,因為我們需要用來相乘,而乘法是從最後一位開始
演算法與設計經典題:大整數乘法(教材2-4)
給定兩個整數u和v,他們分別有m和n為數字,且m≤n,用通常的乘法求uv的值需要O(mn)時間,可以將u和v均看作是有n位數字的大整數,用本章介紹的分治法,在O(n^(log3))時間內計算uv的值,當m<<n時,此法效率不高。設計演算法在O(nlog2/3)時間計算uv的值 在O(
CodeForces - 768B Code For 1 —— 遞迴分治
題意: 把一個數n拆分,奇數拆成n/2,1,n/2,偶數拆成n/2,0,n/2,1和0不可拆,問拆分後從l位置到r位置1的個數 思路: 分治遞迴拆分即可...想的太多... n最大是2^50,最多遞迴呼叫也才是高為50的二叉樹 #include <iostream>
分治法 大整數乘法
學習演算法的時候,其中一道經典就是大整數乘法咯,感覺有點難理解,於是寫一篇部落格加深下理解。 大數相乘不可以直接得到答案,肯定會超出數的範圍,而解決大數相乘的辦法就是分治法:將大問題變成小問題,再變成簡單問題,最後進行合併。 例如:
【演算法】大整數乘法
大整數乘法 問題描述 求兩個不超過200位的非負整數的積。 輸入形式 有兩行,每行是一個不超過200位的非負整數,沒有多餘的前導0。 輸出形式 一行,即相乘後的結果。結果裡不能有多餘的前導0,即如果結果是342,那麼就不能輸出為0342。 樣例輸入 123456789
演算法_遞迴(正整數的冪次方表示)
遞迴 一、概念 函式呼叫自身。 注意:遞迴程式可能更加簡潔,但是不一定節省時間。 二、案例 案例網址:http://cxsjsxmooc.openjudge.cn/2018t2fallw2/2/ 總時間限制: 1000ms 記憶體限制: 65536kB描述 任何一個正整數都可以用2的冪次方表示。例如:
借陣列實現大整數乘法
思想: 用字串來控制輸入,陣列來儲存,陣列的低位存整數的低位,高位來儲存高位, 和:計算的過程基本上和小學生列豎式做加法相同。 差:跟和差不多 乘:計算的過程基本上和列豎式做乘法相同。為程式設計方便,並不急於處理進位,而將進位問題留待最後統一處理 除:基本的思想
C語實現格子乘法--大整數乘法
之前看過有博主發過python版的,看了一看覺得這個方法好玩,小時候老師教的時候又總聽不懂,就想試試看能不能實現起來。 具體的這篇部落格也寫的很清楚了,在這就具體說一說我這個演算法的思路好了。 1.讓使用者輸入兩個大整數以及它們的長度。 2.建立一個二維陣列
Java實現大整數乘法
請設計一個有效的演算法,可以進行兩個n位大整數的乘法運算 1 最暴力的方法:O(n^2) 2 我們採用分而治之的思想 將X和Y按如下方法分成兩部分 那麼 X = A*10^(n/2) + B Y = C*10^(n/2) + D X*
分治法實現大整數乘法【C++語言】
如果實現傳統演算法中兩個n位整數相乘,第一個整數中的n個數字都要分別乘以第二個整數的n個數字,這樣就一共要做n*n次乘法。看上去設計一個乘法次數少於n*n的演算法是不可能的,但事實證明並非如此,可以使用分治的思想計算兩個大整數的相乘。 首先從僅有兩位數字的兩個數12和34考慮,12 = 1 *