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

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

分治法的原理

分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成。(来自度娘的搬运工)

简单的说,分治就是分而治之,把一个问题拆分成几个小问题,最后再汇总解决的办法。

有两点需要记住:

(1) 分治法基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同。

(2)递归的解这些子问题,然后将各子问题的解合并得到原问题的解。

分治法的重点是分析问题是否可以划分为规模较小的子问题,难点是如何划分以及划分之后如何将各个子问题的解合并成最终的解。这一般需要用到数学知识或者其他理论。

下面我们用图来说明:

ec3e2b6a1bbec0f874ea5abcc8944db2.png

通过大整数相乘问题来了解分治法(理想状态下)

这里我们假设有两个大整数X、Y,分别设X=1234、Y=5678。现在要求X*Y的乘积,小学的算法就是把X与Y中的每一项去乘,但是这样的乘法所需的时间复杂度为,效率比较低下。那我们可以采用分治的算法,将X、Y分别拆分为A与B、C与D,如下图:

ecb1843d78510e05e6c321cd31d08562.png

31f867493bed3966a413b0b32d41a7ac.png

注:我们这里取的大整数X、Y是在理想状态下,即X与Y的位数一致,且

f68dc82c8a2c000eccdf2c03bcfe3d49.png

算法分析

首先将X和Y分成A,B,C,D

此时将X和Y的乘积转化为(1)式,把问题转化为求解因式分解的值

在(1)式中,我们一共需要进行4次n/2的乘法(AC2次,AD、BC各一次)和3次加法,因而该算法的时间复杂度为:

d433680cc89c4e8ecae09fe522e90fc4.png

通过master定理可以求得

7397857dc03e9b9b4d92f4d8b7179c52.png,跟小学算法的时间复杂度没有区别。

但是我们再来看看,我们是否可以用加法来换取乘法?因为多一个加法操作,也是常数项,对时间复杂度没有影响,如果减少一个乘法则不同。

(1)式化为:

f6b2b5ebe829e2ca00df763ffdc60b8c.png (2)

现在的时间复杂度为:

cc8e41c655feeb54ac1d9913e9a25d48.png,通过master定理求得,

149dc8b6e6dee4762422c532dac2acf9.png

理想状态下代码实现(部分):

c#:

static void Main(string[] args)

{

//SameNumber();

//UnSameNumber();

UnSameNumber2();

}

static int SIGN(long A)

{

return A > 0 ? 1 : -1;

}

#region 两整数位数相同

private static void SameNumber()

{

Console.Write("请输入两个大整数:\nX=");

long X = Convert.ToInt64(Console.ReadLine());

Console.Write("Y=");

long Y = Convert.ToInt64(Console.ReadLine());

Console.Write("请输入两个大整数的长度:n=");

int n = Convert.ToInt32(Console.ReadLine());

long sum = CalculateSame(X, Y, n);

Console.WriteLine("普通乘法 X*Y={0}*{1}={2}\n", X, Y, X * Y);

Console.WriteLine("分治乘法 X*Y={0}*{1}={2}\n", X, Y, sum);

}

static long CalculateSame(long X, long Y, int n)

{

int sign = SIGN(X) * SIGN(Y);

X = Math.Abs(X);

Y = Math.Abs(Y);

if (X == 0 || Y == 0)

return 0;

else if (n == 1)

return sign * X * Y;

else

{

long A = (long)(X / Math.Pow(10, n / 2));

long B = (long)(X % Math.Pow(10, n / 2));

long C = (long)(Y / Math.Pow(10, n / 2));

long D = (long)(Y % Math.Pow(10, n / 2));

long AC = CalculateSame(A, C, n / 2);

long BD = CalculateSame(B, D, n / 2);

long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

//Console.WriteLine("A={0} B={1} C={2} D={3}\n", A, B, C, D);

return (long)(sign * (AC * Math.Pow(10, n) + ABCD * Math.Pow(10, n / 2) + BD));

}

}

#endregion

75cf1238d6adf8b9a8c99834ec629573.png

大整数相乘算法非理想状态下

这里我们还是假设有两个大整数X、Y,分别设X=123、Y=45678。现在要求X*Y的乘积,乘法所需的时间复杂度为。我们采用分治的算法,将X、Y分别拆分为A与B、C与D,如下图:

dac84a15d0919b169250be4e80e81ce1.png

aa2b783c8a41ddf4da369899fc64c11f.png   (3)

在(3)式中,我们一共需要进行2次xn0的乘法(AC、AD各一次)、2次yn0的乘法(AC、BC各一次)和3次加法,因而该算法的时间复杂度为:

e16134fd4e64689f655df766217c015e.png

现在我们用加法来换取乘法并计算其时间复杂度。

(3)式化为:

d4ee497bf75a0fff61a6350dc2bde9d2.png(4)

现在的时间复杂度为:

8fb844e4098cd112aed2a20fd70adb2b.png

由于

27496840210e038aba71368790265787.png,所以(4)式的时间复杂度小于(3)式的时间复杂度。

非理想状态下代码实现(部分):

c#:

#region 两整数位数不相同

private static void UnSameNumber2()

{

Console.Write("请输入两个大整数:\nX=");

long X = Convert.ToInt64(Console.ReadLine());

Console.Write("Y=");

long Y = Convert.ToInt64(Console.ReadLine());

Console.Write("请输入X的长度:xn=");

int xn = Convert.ToInt32(Console.ReadLine());

Console.Write("请输入Y的长度:yn=");

int yn = Convert.ToInt32(Console.ReadLine());

long sum = CalculateUnSame2(X, Y, xn, yn);

Console.WriteLine("\n普通乘法 X*Y={0}*{1}={2}", X, Y, X * Y);

Console.WriteLine("分治乘法 X*Y={0}*{1}={2}\n", X, Y, sum);

}

static long CalculateUnSame2(long X, long Y, int xn, int yn)

{

if (X == 0 || Y == 0)

return 0;

else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)

return X * Y;

else

{

int xn0 = xn / 2, yn0 = yn / 2;

int xn1 = xn - xn0, yn1 = yn - yn0;

long A = (long)(X / Math.Pow(10, xn0));

long B = (long)(X % Math.Pow(10, xn0));

long C = (long)(Y / Math.Pow(10, yn0));

long D = (long)(Y % Math.Pow(10, yn0));

//Console.WriteLine("A={0}*10^{1} B={2}*10^{3} C={4}*10^{5} D={6}*10^{7}\n", A, xn1, B, xn0, C, yn1, D, yn0);

long AC = CalculateUnSame2(A, C, xn1, yn1);

long BD = CalculateUnSame2(B, D, xn0, yn0);

long ABCD = CalculateUnSame2((long)(A * Math.Pow(10, xn0) - B), (long)(D - C * Math.Pow(10, yn0)), xn1, yn1);

return (long)(2 * AC * Math.Pow(10, (xn0 + yn0)) + ABCD + 2 * BD);

}

}

#endregion

36a61e1ac36cc8f7b1e17fcc0195fe98.png

理想状态下与非理想状态下代码实现(完整):

c语言:

#include

#include

#include

void SameNumber();

void UnSameNumber();

int SIGN(long A);

long CalculateSame(long X, long Y, int n);

long CalculateUnSame(long X, long Y, int xn, int yn);

int main()

{

SameNumber();

UnSameNumber();

return (0);

}

int SIGN(long A)

{

return A > 0 ? 1 : -1;

}

void SameNumber()

{

long X=0,Y = 0;

int n=0;

printf("理想状态下用法!");

printf("请输入两个大整数:\nX=");

scanf("%d",&X);

printf("Y=");

scanf("%d",&Y);

printf("请输入两个大整数的长度:n=");

scanf("%d",&n);

long sum = CalculateSame(X, Y, n);

printf("普通乘法 X*Y=%d*%d=%d\n",X,Y,X*Y);

printf("分治乘法 X*Y=%d*%d=%d\n",X,Y,sum);

}

long CalculateSame(long X, long Y, int n)

{

int sign = SIGN(X) * SIGN(Y);

X = labs(X);

Y = labs(Y);

if (X == 0 || Y == 0)

return 0;

else if (n == 1)

return sign * X * Y;

else

{

long A = (long)(X / pow(10, n / 2));

long B = (X % (long)pow(10, n / 2));

long C = (long)(Y / pow(10, n / 2));

long D = (Y % (long)pow(10, n / 2));

long AC = CalculateSame(A, C, n / 2);

long BD = CalculateSame(B, D, n / 2);

long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

//cout<

return (long)(sign * (AC * pow(10, n) + ABCD * pow(10, n / 2) + BD));

}

}

void UnSameNumber()

{

long X=0,Y = 0;

int xn=0,yn=0;

printf("非理想状态下用法!");

printf("请输入两个大整数:\nX=");

scanf("%d",&X);

printf("Y=");

scanf("%d",&Y);

printf("请输入X的长度:xn=");

scanf("%d",&xn);

printf("请输入Y的长度:xn=");

scanf("%d",&yn);

long sum = CalculateUnSame(X, Y, xn,yn);

printf("普通乘法 X*Y=%d*%d=%d\n",X,Y,X*Y);

printf("分治乘法 X*Y=%d*%d=%d\n",X,Y,sum);

}

long CalculateUnSame(long X, long Y, int xn, int yn)

{

if (X == 0 || Y == 0)

return 0;

else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)

return X * Y;

else

{

int xn0 = xn / 2, yn0 = yn / 2;

int xn1 = xn - xn0, yn1 = yn - yn0;

long A = (long)(X / pow(10, xn0));

long B = (long)(X % (long)pow(10, xn0));

long C = (long)(Y / pow(10, yn0));

long D = (long)(Y % (long)pow(10, yn0));

long AC = CalculateUnSame(A, C, xn1, yn1);

long BD = CalculateUnSame(B, D, xn0, yn0);

long ABCD = CalculateUnSame((long)(A * pow(10, xn0) - B), (long)(D - C * pow(10, yn0)), xn1, yn1);

return (long)(2 * AC * pow(10, (xn0 + yn0)) + ABCD + 2 * BD);

}

}

c++语言:

#include

#include

#include

int count=0;

using namespace std;

void SameNumber();

void UnSameNumber();

int SIGN(long A);

long CalculateSame(long X, long Y, int n);

long CalculateUnSame(long X, long Y, int xn, int yn);

int main()

{

SameNumber();

UnSameNumber();

return (0);

}

int SIGN(long A)

{

return A > 0 ? 1 : -1;

}

void SameNumber()

{

cout<

cout<

long X = 0;

cin>>X;

cout<

long Y = 0;

cin>>Y;

cout<

int n = 0;

cin>>n;

long sum = CalculateSame(X, Y, n);

cout<

cout<

}

long CalculateSame(long X, long Y, int n)

{

int sign = SIGN(X) * SIGN(Y);

X = abs(X);

Y = abs(Y);

if (X == 0 || Y == 0)

return 0;

else if (n == 1)

return sign * X * Y;

else

{

long A = (long)(X / pow(10, n / 2));

long B = (X % (long)pow(10, n / 2));

long C = (long)(Y / pow(10, n / 2));

long D = (Y % (long)pow(10, n / 2));

long AC = CalculateSame(A, C, n / 2);

long BD = CalculateSame(B, D, n / 2);

long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

cout<

return (long)(sign * (AC * pow(10, n) + ABCD * pow(10, n / 2) + BD));

}

}

void UnSameNumber()

{

cout<

cout<

long X = 0;

cin>>X;

cout<

long Y = 0;

cin>>Y;

cout<

int xn = 0;

cin>>xn;

cout<

int yn = 0;

cin>>yn;

long sum = CalculateUnSame(X, Y, xn,yn);

cout<

cout<

}

long CalculateUnSame(long X, long Y, int xn, int yn)

{

if (X == 0 || Y == 0)

return 0;

else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)

return X * Y;

else

{

int xn0 = xn / 2, yn0 = yn / 2;

int xn1 = xn - xn0, yn1 = yn - yn0;

long A = (long)(X / pow(10, xn0));

long B = (long)(X % (long)pow(10, xn0));

long C = (long)(Y / pow(10, yn0));

long D = (long)(Y % (long)pow(10, yn0));

long AC = CalculateUnSame(A, C, xn1, yn1);

long BD = CalculateUnSame(B, D, xn0, yn0);

long ABCD = CalculateUnSame((long)(A * pow(10, xn0) - B), (long)(D - C * pow(10, yn0)), xn1, yn1);

return (long)(2 * AC * pow(10, (xn0 + yn0)) + ABCD + 2 * BD);

}

}

c#语言:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace BigInteger

{

class Program

{

static void Main(string[] args)

{

SameNumber();

UnSameNumber();

}

static int SIGN(long A)

{

return A > 0 ? 1 : -1;

}

#region 两整数位数相同

private static void SameNumber()

{

Console.Write("请输入两个大整数:\nX=");

long X = Convert.ToInt64(Console.ReadLine());

Console.Write("Y=");

long Y = Convert.ToInt64(Console.ReadLine());

Console.Write("请输入两个大整数的长度:n=");

int n = Convert.ToInt32(Console.ReadLine());

long sum = CalculateSame(X, Y, n);

Console.WriteLine("普通乘法 X*Y={0}*{1}={2}\n", X, Y, X * Y);

Console.WriteLine("分治乘法 X*Y={0}*{1}={2}\n", X, Y, sum);

}

static long CalculateSame(long X, long Y, int n)

{

int sign = SIGN(X) * SIGN(Y);

X = Math.Abs(X);

Y = Math.Abs(Y);

if (X == 0 || Y == 0)

return 0;

else if (n == 1)

return sign * X * Y;

else

{

long A = (long)(X / Math.Pow(10, n / 2));

long B = (long)(X % Math.Pow(10, n / 2));

long C = (long)(Y / Math.Pow(10, n / 2));

long D = (long)(Y % Math.Pow(10, n / 2));

long AC = CalculateSame(A, C, n / 2);

long BD = CalculateSame(B, D, n / 2);

long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

return (long)(sign * (AC * Math.Pow(10, n) + ABCD * Math.Pow(10, n / 2) + BD));

}

}

#endregion

#region 两整数位数不相同

private static void UnSameNumber()

{

Console.Write("请输入两个大整数:\nX=");

long X = Convert.ToInt64(Console.ReadLine());

Console.Write("Y=");

long Y = Convert.ToInt64(Console.ReadLine());

Console.Write("请输入X的长度:xn=");

int xn = Convert.ToInt32(Console.ReadLine());

Console.Write("请输入Y的长度:yn=");

int yn = Convert.ToInt32(Console.ReadLine());

long sum = CalculateUnSame(X, Y, xn, yn);

Console.WriteLine("\n普通乘法 X*Y={0}*{1}={2}", X, Y, X * Y);

Console.WriteLine("分治乘法 X*Y={0}*{1}={2}\n", X, Y, sum);

}

static long CalculateUnSame(long X, long Y, int xn, int yn)

{

if (X == 0 || Y == 0)

return 0;

else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)

return X * Y;

else

{

int xn0 = xn / 2, yn0 = yn / 2;

int xn1 = xn - xn0, yn1 = yn - yn0;

long A = (long)(X / Math.Pow(10, xn0));

long B = (long)(X % Math.Pow(10, xn0));

long C = (long)(Y / Math.Pow(10, yn0));

long D = (long)(Y % Math.Pow(10, yn0));

long AC = CalculateUnSame(A, C, xn1, yn1);

long BD = CalculateUnSame(B, D, xn0, yn0);

long ABCD = CalculateUnSame((long)(A * Math.Pow(10, xn0) - B), (long)(D - C * Math.Pow(10, yn0)), xn1, yn1);

return (long)(2 * AC * Math.Pow(10, (xn0 + yn0)) + ABCD + 2 * BD);

}

}

#endregion

}

}

Java语言:

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

import java.io.*;

import java.util.Scanner;

import java.util.Collections;

import java.util.Comparator;

import java.util.Random;

public class Program

{

public static Scanner sc = new Scanner(System.in);

public static int count=0;

public static void main(String[] args)

{

SameNumber();

UnSameNumber();

}

public static int SIGN(long A)

{

return A > 0 ? 1 : -1;

}

//两整数位数相同

private static void SameNumber()

{

System.out.print("请输入两个大整数:\nX=");

long X = sc.nextLong();

System.out.print("Y=");

long Y = sc.nextLong();

System.out.print("请输入两个大整数的长度:n=");

int n = sc.nextInt();

long sum = CalculateSame(X, Y, n);

System.out.println("普通乘法 X*Y="+X+"*"+Y+"="+X*Y+"\n");

System.out.println("分治乘法 X*Y="+X+"*"+Y+"="+sum+"\n");

}

public static long CalculateSame(long X, long Y, int n)

{

int sign = SIGN(X) * SIGN(Y);

X = Math.abs(X);

Y = Math.abs(Y);

if (X == 0 || Y == 0)

return 0;

else if (n == 1)

return sign * X * Y;

else

{

long A = (long)(X / Math.pow(10, n / 2));

long B = (long)(X % Math.pow(10, n / 2));

long C = (long)(Y / Math.pow(10, n / 2));

long D = (long)(Y % Math.pow(10, n / 2));

long AC = CalculateSame(A, C, n / 2);

long BD = CalculateSame(B, D, n / 2);

long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

return (long)(sign * (AC * Math.pow(10, n) + ABCD * Math.pow(10, n / 2) + BD));

}

}

//两整数位数不同

private static void UnSameNumber()

{

System.out.print("请输入两个大整数:\nX=");

long X = sc.nextLong();

System.out.print("Y=");

long Y = sc.nextLong();

System.out.print("请输入X的长度:xn=");

int xn = sc.nextInt();

System.out.print("请输入Y的长度:yn=");

int yn = sc.nextInt();

long sum = CalculateUnSame(X, Y, xn, yn);

System.out.println("普通乘法 X*Y="+X+"*"+Y+"="+X*Y+"\n");

System.out.println("分治乘法 X*Y="+X+"*"+Y+"="+sum+"\n");

}

public static long CalculateUnSame(long X, long Y, int xn, int yn)

{

if (X == 0 || Y == 0)

return 0;

else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)

return X * Y;

else

{

int xn0 = xn / 2, yn0 = yn / 2;

int xn1 = xn - xn0, yn1 = yn - yn0;

long A = (long)(X / Math.pow(10, xn0));

long B = (long)(X % Math.pow(10, xn0));

long C = (long)(Y / Math.pow(10, yn0));

long D = (long)(Y % Math.pow(10, yn0));

long AC = CalculateUnSame(A, C, xn1, yn1);

long BD = CalculateUnSame(B, D, xn0, yn0);

long ABCD = CalculateUnSame((long)(A * Math.pow(10, xn0) - B), (long)(D - C * Math.pow(10, yn0)), xn1, yn1);

return (long)(2 * AC * Math.pow(10, (xn0 + yn0)) + ABCD + 2 * BD);

}

}

}

JavaScript语言:

function SIGN(A)

{

return A > 0 ? 1 : -1;

}

function SameNumber()

{

var str = "";

var X = document.getElementById('SX').value;

var Y = document.getElementById('SY').value;

var n = document.getElementById('Sn').value;

var sum = CalculateSame(X, Y, n);

str += "普通乘法 X*Y="+X+"*"+Y+"="+X * Y+"
";

str += "分治乘法 X*Y="+X+"*"+Y+"="+sum;

document.getElementById('oldcontent').innerHTML = str;

}

function CalculateSame(X, Y, n)

{

var sign = SIGN(X) * SIGN(Y);

X = Math.abs(X);

Y = Math.abs(Y);

if (X == 0 || Y == 0)

return 0;

else if (n == 1)

return sign * X * Y;

else

{

var A = parseInt(X / Math.pow(10, n / 2));

var B = parseInt(X % Math.pow(10, n / 2));

var C = parseInt(Y / Math.pow(10, n / 2));

var D = parseInt(Y % Math.pow(10, n / 2));

var AC = CalculateSame(A, C, n / 2);

var BD = CalculateSame(B, D, n / 2);

var ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

return (sign * (AC * Math.pow(10, n) + ABCD * Math.pow(10, n / 2) + BD));

}

}

function UnSameNumber()

{

var str = "";

var X = document.getElementById('KX').value;

var Y = document.getElementById('KY').value;

var xn = document.getElementById('xn').value;

var yn = document.getElementById('yn').value;

var sum = CalculateUnSame(X, Y, xn, yn);

str += "普通乘法 X*Y="+X+"*"+Y+"="+X * Y+"
";

str += "分治乘法 X*Y="+X+"*"+Y+"="+sum;

document.getElementById('newcontent').innerHTML = str;

}

function CalculateUnSame(X,Y,xn,yn)

{

if (X == 0 || Y == 0)

return 0;

else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)

return X * Y;

else

{

var xn0 = parseInt(xn / 2), yn0 = parseInt(yn / 2);

var xn1 = xn - xn0, yn1 = yn - yn0;

var A = parseInt(X / Math.pow(10, xn0));

var B = parseInt(X % Math.pow(10, xn0));

var C = parseInt(Y / Math.pow(10, yn0));

var D = parseInt(Y % Math.pow(10, yn0));

var AC = CalculateUnSame(A, C, xn1, yn1);

var BD = CalculateUnSame(B, D, xn0, yn0);

var ABCD = CalculateUnSame((A * Math.pow(10, xn0) - B), (D - C * Math.pow(10, yn0)), xn1, yn1);

return (2 * AC * Math.pow(10, (xn0 + yn0)) + ABCD + 2 * BD);

}

}

请输入两个大整数:X= Y= 请输入两个大整数的长度:n=
请输入两个大整数:X= Y= 请输入X的长度:xn=请输入Y的长度:yn=

PHP语言:

error_reporting(E_ALL ^ E_NOTICE);

SameNumber();

UnSameNumber();

function SameNumber()

{

fwrite(STDOUT, "理想状态算法!\n请输入两个大整数:\nX=");

$X = trim(fgets(STDIN));

fwrite(STDOUT, "Y=");

$Y = trim(fgets(STDIN));

fwrite(STDOUT, "请输入两个大整数的长度:n=");

$n = trim(fgets(STDIN));

$sum = CalculateSame($X, $Y, $n);

echo "普通乘法 X*Y=".$X."*".$Y."=".$X*$Y."\n";

echo "分治乘法 X*Y=".$X."*".$Y."=".$sum."\n";

}

function SIGN($A)

{

return $A > 0 ? 1 : -1;

}

function CalculateSame($X,$Y,$n)

{

$sign = SIGN($X) * SIGN($Y);

$X = abs($X);

$Y = abs($Y);

if ($X == 0 || $Y == 0)

return 0;

else if ($n == 1)

return $sign * $X * $Y;

else

{

$A = intval($X / pow(10, $n / 2));

$B = intval($X % pow(10, $n / 2));

$C = intval($Y / pow(10, $n / 2));

$D = intval($Y % pow(10, $n / 2));

//echo"sign=".$sign." pow=".pow(10, $n / 2)." X=".$X." Y=".$Y." A=".$A." B=".$B." C=".$C." D=".$D."\n";

$AC = CalculateSame($A, $C, $n / 2);

$BD = CalculateSame($B, $D, $n / 2);

$ABCD = CalculateSame(($A - $B), ($D - $C), $n / 2) + $AC + $BD;

//echo "sum=".( $AC * pow(10, $n) )." AC=".$AC." BD=".$BD." ABCD=".$ABCD."\n";

return ($sign * ($AC * pow(10, $n) + $ABCD * pow(10, $n / 2) + $BD));

}

}

function UnSameNumber()

{

fwrite(STDOUT, "\n非理想状态!\n请输入两个大整数:\nX=");

$X = trim(fgets(STDIN));

fwrite(STDOUT, "Y=");

$Y = trim(fgets(STDIN));

fwrite(STDOUT, "请输入X的长度:xn=");

$xn = trim(fgets(STDIN));

fwrite(STDOUT, "请输入Y的长度:yn=");

$yn = trim(fgets(STDIN));

$sum = CalculateUnSame($X, $Y, $xn,$yn);

echo "普通乘法 X*Y=".$X."*".$Y."=".$X*$Y."\n";

echo "分治乘法 X*Y=".$X."*".$Y."=".$sum."\n";

}

function CalculateUnSame($X,$Y,$xn,$yn)

{

if ($X == 0 || $Y == 0)

return 0;

else if (($xn == 1 && $yn == 1) || $xn == 1 || $yn == 1)

return $X * $Y;

else

{

$xn0 = intval($xn / 2);

$yn0 = intval($yn / 2);

$xn1 = $xn - $xn0;

$yn1 = $yn - $yn0;

$A = intval($X / pow(10, $xn0));

$B = intval($X % pow(10, $xn0));

$C = intval($Y / pow(10, $yn0));

$D = intval($Y % pow(10, $yn0));

echo"X=".$X." Y=".$Y." A=".$A." B=".$B." C=".$C." D=".$D."\n";

$AC = CalculateUnSame($A, $C, $xn1, $yn1);

$BD = CalculateUnSame($B, $D, $xn0, $yn0);

$ABCD = CalculateUnSame(($A * pow(10, $xn0) - $B), ($D - $C * pow(10, $yn0)), $xn1, $yn1);

//echo "sum=".( $AC * pow(10, $n) )." AC=".$AC." BD=".$BD." ABCD=".$ABCD."\n";

return (2 * $AC * pow(10, ($xn0 + $yn0)) + $ABCD + 2 * $BD);

}

}

?>

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
矩阵乘法是计算机科学中非常基础的一种算,它在图像处理、人工智能等领域都有广泛的应用。而分治是一种常见的算思想,它可以将一个问题分成多个子问题,再将子问题的结果合并起来得到最终结果。本文将介绍如何使用分治实现矩阵乘法。 首先,我们来回顾一下矩阵乘法的定义。对于矩阵A和B,它们的乘积C的第i行第j列的元素可以表示为: C[i][j] = sum(A[i][k] * B[k][j]), k = 1,2,...,n 其中n为矩阵的大小。 接下来,我们将使用分治来实现矩阵乘法。具体思路如下: 1.将矩阵A和B分别划分成4个子矩阵,即A11、A12、A21、A22和B11、B12、B21、B22。 2.递归地计算子矩阵的乘积,得到C11、C12、C21和C22。 3.将C11、C12、C21和C22合并成一个大的矩阵C。 下面是Python代码实现: ```python def matrix_multiply(A, B): # 判断矩阵大小是否相等 assert len(A[0]) == len(B) # 矩阵大小为1x1的情况 if len(A) == 1 and len(A[0]) == 1 and len(B) == 1 and len(B[0]) == 1: return [[A[0][0] * B[0][0]]] # 将矩阵A和B分成4个子矩阵 A11, A12, A21, A22 = split_matrix(A) B11, B12, B21, B22 = split_matrix(B) # 递归地计算子矩阵的乘积 C11 = matrix_add(matrix_multiply(A11, B11), matrix_multiply(A12, B21)) C12 = matrix_add(matrix_multiply(A11, B12), matrix_multiply(A12, B22)) C21 = matrix_add(matrix_multiply(A21, B11), matrix_multiply(A22, B21)) C22 = matrix_add(matrix_multiply(A21, B12), matrix_multiply(A22, B22)) # 合并C11、C12、C21和C22成一个大的矩阵C return merge_matrix(C11, C12, C21, C22) def split_matrix(matrix): # 将矩阵按行、列均分为两个子矩阵 n = len(matrix) m = len(matrix[0]) A = [[matrix[i][j] for j in range(m // 2)] for i in range(n // 2)] B = [[matrix[i][j] for j in range(m // 2, m)] for i in range(n // 2)] C = [[matrix[i][j] for j in range(m // 2)] for i in range(n // 2, n)] D = [[matrix[i][j] for j in range(m // 2, m)] for i in range(n // 2, n)] return A, B, C, D def merge_matrix(A, B, C, D): # 将四个子矩阵合并成一个大的矩阵 n = len(A) + len(C) m = len(A[0]) + len(B[0]) matrix = [[0] * m for i in range(n)] for i in range(len(A)): for j in range(len(A[0])): matrix[i][j] = A[i][j] for i in range(len(C)): for j in range(len(C[0])): matrix[i + len(A)][j] = C[i][j] for i in range(len(B)): for j in range(len(B[0])): matrix[i][j + len(A[0])] = B[i][j] for i in range(len(D)): for j in range(len(D[0])): matrix[i + len(A)][j + len(A[0])] = D[i][j] return matrix def matrix_add(A, B): # 矩阵加 n = len(A) m = len(A[0]) matrix = [[0] * m for i in range(n)] for i in range(n): for j in range(m): matrix[i][j] = A[i][j] + B[i][j] return matrix ``` 可以使用以下代码进行测试: ```python A = [[1, 2], [3, 4]] B = [[5, 6], [7, 8]] C = matrix_multiply(A, B) print(C) # [[19, 22], [43, 50]] ``` 上面的代码实现了分治实现矩阵乘法的基本思路,但是它的时间复杂度依然是O(n^3),因为我们在合并子问题的结果时需要遍历整个矩阵。实际上,我们可以在递归计算子问题时将子矩阵的结果直接传递到合并函数中,这样可以避免重复计算,从而将时间复杂度优化到O(n^2.81)。感兴趣的读者可以自行了解 Strassen 算的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值