大整数乘法-分治算法
分治算法思想
将问题分为k个子问题,对这k个子问题分别求解。如果子问题的规模仍然不够小,则每个子问题再划分为k个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止。
问题分析
这个问题的时间复杂度我似懂非懂,想知道其中的具体过程的请自行百度。
对于两个数字X、Y,传统计算方式的时间复杂度是O(n^2)
。
那么我们可以根据高位低位进行分隔,例如:
其中,xn0
、xn1
分别为A、B的位数,yn0
、yn1
同理。那么X*Y
可写成如下结果:
\[\begin{align}X*Y &= (A*10^{xn1}+B)(C*10^{yn1}+D)\ &= AC*10^{xn1+yn1}+AD*10^{xn1}+BC*10^{yn1}+BD\end{align}\]
由于我们需要计算4次大整数乘积,所以算法复杂度依然时O(n^2)
。
为了减小时间复杂度,我们进行如下改动:
令:
\[ABCD = (A*10^{xn1}-B)(D-C*10^{yn1})\]
展开可得:
\[ABCD = AD*10^{xn1}-AC*10^{xn1+yn1}-BD+BC*10^{yn1}\]
综上可得:
\[X*Y = ABCD+2AC*10^{xn1+yn1}+2BD\]
现在我们将时间复杂度降低到了O(n^1.59)
。
C++代码
#include<iostream> #include<cmath> typedef long long ll; using namespace std; void AcceptAndCompute(); int SizeNumber(ll num); ll Compute(ll X, ll Y, int xn, int yn); int Sign(ll x); int main() { AcceptAndCompute(); return 0; } void AcceptAndCompute() { ll X, Y; cout<<"输入X,Y的值:"<<endl; cout<<"X: "; cin>>X; cout<<"Y: "; cin>>Y; cout<<"直接计算结果:"<<X*Y<<endl; // 直接运算 int xn, yn; xn = SizeNumber(abs(X)); yn = SizeNumber(abs(Y)); int sign_x, sign_y; sign_x = Sign(X); sign_y = Sign(Y); X = abs(X); Y = abs(Y); cout<<"分治计算结果:"<<ll(Compute(X, Y, xn, yn)*sign_x*sign_y)<<endl; } int SizeNumber(ll num) // 计算num有多少位 { return int(log10(num)) + 1; } int Sign(ll x) // 获取符号 { return x > 0 ? 1 : -1; } ll Compute(ll X, ll Y, int xn, int yn) { if(!X || !Y) return 0; if(xn == 1 || yn == 1) return X * Y; int xn0 = xn / 2, yn0 = yn / 2; int xn1 = xn - xn0, yn1 = yn - yn0; ll A = ll(X / ll(pow(10, xn1))); ll B = ll(X % ll(pow(10, xn1))); ll C = ll(Y / ll(pow(10, yn1))); ll D = ll(Y % ll(pow(10, yn1))); ll AC = Compute(A, C, xn0, yn0); ll BD = Compute(B, D, xn1, yn1); ll ABCD = Compute(ll(A*pow(10,xn1)-B), ll(D-C*pow(10, yn1)), xn0, yn0); return ll(2*AC*pow(10, (xn1+yn1))+ABCD+2*BD); }