分治法——大整数相乘

大整数相乘:A、B两个整数,A有n位(123456……n),B有m位(123456……m),一般的思路是像最初学习乘法时一样逐位相乘后相加,但是这样做算法的复杂度过高,但这仍然是解题的基本思想。

既然提到分治,那么如何分,怎么治?

分:

能够找到一个大问题划分为小问题方法的重要技巧是能够看到大问题的规模和所谓规模的单位。在大整数相乘中大问题的规模就是一个n位的整数要乘以一个m位的整数,所谓规模的单位就是“位”。而“分”的目的就是把大规模拆分为小规模,把小单位转变为大单位,这两句是一个意思,也就是说我们可以把规模n变成n/2和n/2(把以1位为单位规模为n的问题 变成 以n/2为单位的规模为2的问题),把规模m变成m/2和m/2(把以1位为单位规模为m的问题 变成 以m/2为单位的规模为2的问题),如此,原来的大整数相乘就变成了两个2位数相乘,只不过低位向高位的进制不再是10,而是10^{n/2}10^{m/2}。更一般地,我们把整数A由规模n分为n1和n2,把整数B由规模m分为m1和m2,如下图:

     ​             

则A分为n1位的A1和n2位,B分为m1位的B1和m2位的B2,如下式所示:

A=A1\times 10^{n2}+A2

B=B1\times10^{m2}+B2;

以此类推,我们可以把A1、A2、B1、B2继续划分,直至最小单位。(这里在编程时需要用递归来实现)

治:

上面讲的很清楚了,那么A和B的相乘就可以表示为:

AB=(A1\times10^{n2}+A2)\times(B1\times10^{m2}+B2)=A1B1\times10^{n2+m2}+A2B1\times10^{m2}+A1B2\times10^{n2}+A2B2

现在是要计算四个大整数相乘,我们可以通过变换使得上式变成三个大整数相乘,如下式:(从上式到下式的思路没想到,可能是缺乏经验吧,待大神指点。)

AB=(A1\times10^{n2}+A2)\times(B1\times10^{m2}+B2)=A1B1\times10^{n2+m2}+A2B1\times10^{m2}+A1B2\times10^{n2}+A2B2=2\times A1B1\times10^{n2+m2}+2\times A2B2+(A1 \times10^{n2}-A2)(B2-B1\times10^{m2})

*上述讲解纯属个人见解,欢迎提出问题。

C++实现代码:

下面实现的是输入两个大数,A和B,输出AxB的解。

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

string multi(string A, string B); //计算大整数相乘
string Plus(string q, string w, string e, string r); //计算大整数相加
stringstream ss;

int main() {
    string A, B;

    while (cin >> A >> B) {
        cout << multi(A, B) << endl;
    }
    return 0;
}

string multi(string A, string B) {
    int len_A = A.length();
    int len_B = B.length();
    if (len_A == 1) {
        if (len_B == 1) { //最基本的情况:A和B都是一位数,把A、B从string转为int(我这里用的stringstream),然后相乘后转回为string型return回去。
            ss << A;
            int a;
            ss >> a;
            ss.clear();
            ss << B;
            int b;
            ss >> b;
            ss.clear();
            ss << b*a;
            string str_out;
            ss >> str_out;
            ss.clear();
            return str_out;
        }
        else {  //A是个位数,B不是的情况下,按照分治的思想把B分开分别与A相乘。
            string B1, B2;
            B1 = B.substr(0, len_B / 2);
            B2 = B.substr(len_B / 2);
            string AB1 = multi(A, B1);
            string AB2 = multi(A, B2);
            if (AB2.length() > B2.length()) {
                string str = AB2.substr(0, 1);
                ss << str;
                int ab2;
                ss >> ab2;
                ss.clear();
                ss << AB1;
                int ab1;
                ss >> ab1;
                ss.clear();
                ss << ab1 + ab2;
                ss >> AB1;
                ss.clear();
                return AB1 + AB2.substr(1);
            }
            else
                return AB1 + AB2;
        }
    }
    else {
        if (len_B == 1) {  //B是个位数,A不是的情况与上述A是个位数B不是的情况相同。
            string A1, A2;
            A1 = A.substr(0, len_A / 2);
            A2 = A.substr(len_A / 2);
            string A1B = multi(A1, B);
            string A2B = multi(A2, B);
            if (A2B.length() > A2.length()) {
                string str = A2B.substr(0, 1);
                ss << str;
                int a2b;
                ss >> a2b;
                ss.clear();
                ss << A1B;
                int a1b;
                ss >> a1b;
                ss.clear();
                ss << a1b + a2b;
                ss >> A1B;
                ss.clear();
                return A1B + A2B.substr(1);
            }
            else {
                return A1B + A2B;
            }
        }
        else {  //A和B都不是个位数,就按照上述方法分治就可以了,只是为了最后相加的时候方便,把返回的四个部分都用0凑成了位数相同的。
            string A1, A2, B1, B2;
            A1 = A.substr(0, len_A / 2);
            A2 = A.substr(len_A / 2);
            B1 = B.substr(0, len_B / 2);
            B2 = B.substr(len_B / 2);
            string part1_ = multi(A1, B1);
            string part1_0(A2.length()+B2.length(), '0');
            part1_ = part1_ + part1_0;
            string part2_ = multi(A2, B2);
            string part2_00(part1_.length() - part2_.length(), '0');
            part2_ = part2_00 + part2_;
            string part3_ = multi(A1, B2);
            string part3_0(A2.length(), '0');
            part3_ = part3_ + part3_0;
            string part3_00(part1_.length() - part3_.length(), '0');
            part3_ = part3_00 + part3_;
            string part4_ = multi(A2, B1);
            string part4_0(B2.length(), '0');
            part4_ = part4_ + part4_0;
            string part4_00(part1_.length() - part4_.length(), '0');
            part4_ = part4_00 + part4_;
            return Plus(part1_, part2_, part3_, part4_);
        }
    }
}

string Plus(string q, string w, string e, string r) { //大整数相加
    int len_q = q.length();
    string y, out;
    int a, b, c, d;
    for (int i = 1; i <= len_q; i++) {
        ss << q.substr(len_q - i, 1);
        ss >> a;
        ss.clear();
        ss << w.substr(len_q - i, 1);
        ss >> b;
        ss.clear();
        ss << e.substr(len_q - i, 1);
        ss >> c;
        ss.clear();
        ss << r.substr(len_q - i, 1);
        ss >> d;
        ss.clear();
        ss << a + b + c + d;
        ss >> y;
        ss.clear();
        if (i == 1)
            out = y;
        else if (out.length() > i - 1) {
            ss << out.substr(0, 1);
            ss >> a;
            ss.clear();
            ss << y;
            ss >> b;
            ss.clear();
            ss << a + b;
            ss >> y;
            ss.clear();
            out = y + out.substr(1);
        }
        else {
            out = y + out;
        }
    }
    return out;
}

猜你喜欢

转载自blog.csdn.net/qq_36165148/article/details/81132525
今日推荐