大整数乘法-分治算法

分治算法思想

将问题分为k个子问题,对这k个子问题分别求解。如果子问题的规模仍然不够小,则每个子问题再划分为k个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止。

大整数乘法-分治算法

问题分析

这个问题的时间复杂度我似懂非懂,想知道其中的具体过程的请自行百度。

对于两个数字X、Y,传统计算方式的时间复杂度是O(n^2)
那么我们可以根据高位低位进行分隔,例如:

大整数乘法-分治算法

其中,xn0xn1分别为A、B的位数,yn0yn1同理。那么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);
}

感谢

分治法的经典问题——大整数相乘