MIT-两个多项式相乘
文章目录
- 问题描述
- 算法实现
- 暴力算法
- 分治算法
- Karatsuba(优化的分治算法)
问题描述
给定两个次数为 nnn 的多项式:
A(x)=a0+a1x+⋯+anxnB(x)=b0+b1x+⋯+bnxn\begin{gathered}A(x)=a_0+a_1x+\cdots+a_nx^n\\B(x)=b_0+b_1x+\cdots+b_nx^n\end{gathered}A(x)=a0+a1x+⋯+anxnB(x)=b0+b1x+⋯+bnxn
求它们的积 A(x)⋅B(x)A(x)\cdot B(x)A(x)⋅B(x)。
算法实现
暴力算法
我们设 A(x)=∑i=0naixiA(x)=\sum_{i=0}^{n}a_{i}x^{i}A(x)=∑i=0naixi ,B(x)=∑i=0nbixiB(x)=\sum_{i=0}^{n}b_{i}x^{i}B(x)=∑i=0nbixi 和 C(x)=∑k=02ncixi=A(x)B(x)C(x)=\sum_{k=0}^{2n}c_{i}x^{i}=A(x)B(x)C(x)=∑k=02ncixi=A(x)B(x)。其中 ck=∑i=0kaibk−ic_k=\sum_{i=0}^ka_ib_{k-i}ck=∑i=0kaibk−i ,0≤k≤2n0\leq k\leq 2n0≤k≤2n。
int* Brute_PolynomialMultiply(int a[], int b[], int n)
{int m = 2 * n;int c[m];for (int k = 0; k <= m; k ++ ){for (int i = 0; i <= k; i ++ )c[k] += a[i] * b[k - i];}return c;
}
时间复杂度 :O(n2)O(n^2)O(n2)
分治算法
考虑到多项式乘法问题的结构性质,我们可以采用分治算法。该算法的核心思想是将大问题分解为多个较小的子问题,利用分治策略递归地解决这些子问题,从而减少计算量。
在多项式乘法中,我们可以将每个多项式分解为两部分,并递归地计算这些部分的乘积。具体来说,我们定义
A0(x)=a0+a1x+⋯+a⌊n2⌋−1x⌊n2⌋−1,A1(x)=a⌊n2⌋+a⌊n2⌋+1x+⋯+anxn−⌊n2⌋.\begin{array}{rcl}A_0(x)&=&a_0+a_1x+\cdots+a_{\lfloor\frac{n}{2}\rfloor-1}x^{\lfloor\frac{n}{2}\rfloor-1},\\A_1(x)&=&a_{\lfloor\frac{n}{2}\rfloor}+a_{\lfloor\frac{n}{2}\rfloor+1}x+\cdots+a_nx^{n-\lfloor\frac{n}{2}\rfloor}.\end{array}A0(x)A1(x)==a0+a1x+⋯+a⌊2n⌋−1x⌊2n⌋−1,a⌊2n⌋+a⌊2n⌋+1x+⋯+anxn−⌊2n⌋.
多项式A(x)A(x)A(x) 可写成 A(x)=A0(x)+xn/2A1(x)A(x)=A_0(x)+x^{n/2}A_1(x)A(x)=A0(x)+xn/2A1(x) 的形式 。
同样的,我们也可以像上述一样定义 B0(x)B_0(x)B0(x) 和 B1(x)B_1(x)B1(x),多项式 B(x)B(x)B(x) 可写成下面的形式:
B(x)=B0(x)+B1(x)x⌊n2⌋B(x)=B_{0}(x)+B_{1}(x)x^{\lfloor\frac{n}{2}\rfloor}B(x)=B0(x)+B1(x)x⌊2n⌋
所以,我们可以通过以下方式计算它们的乘积:
A(x)B(x)=A0(x)B0(x)+A0(x)B1(x)x⌊n2⌋+A1(x)B0(x)x⌊n2⌋+A1(x)B1(x)x2⌊n2⌋A(x)B(x)=A_{0}(x)B_{0}(x)+A_{0}(x)B_{1}(x)x^{\lfloor\frac{n}{2}\rfloor}+A_{1}(x)B_{0}(x)x^{\lfloor\frac{n}{2}\rfloor}+A_{1}(x)B_{1}(x)x^{2\lfloor\frac{n}{2}\rfloor}A(x)B(x)=A0(x)B0(x)+A0(x)B1(x)x⌊2n⌋+A1(x)B0(x)x⌊2n⌋+A1(x)B1(x)x2⌊2n⌋
这样就将原来问题规模为 nnn 的问题分割成 444 个 n2\frac{n}{2}2n 的子问题了,分别为:
U(x)=A0(x)B0(x),V(x)=A0(x)B1(x),W(x)=A1(x)B0(x),Z(x)=A1(x)B1(x)\begin{array}{cc}U(x)=A_0(x)B_0(x),&V(x)=A_0(x)B_1(x),\\W(x)=A_1(x)B_0(x),&Z(x)=A_1(x)B_1(x)\end{array}U(x)=A0(x)B0(x),W(x)=A1(x)B0(x),V(x)=A0(x)B1(x),Z(x)=A1(x)B1(x)

// 多项式相加
vector<int> addPoly(const vector<int>& A, const vector<int>& B) {int n = max(A.size(), B.size());vector<int> result(n, 0);for (int i = 0; i < n; i++) {if (i < A.size()) result[i] += A[i];if (i < B.size()) result[i] += B[i];}return result;
}vector<int> DC_multiplyPoly(const vector<int>& A, const vector<int>& B) {int n = A.size();// 基本情况if (A.empty() || B.empty()) return {};if (n == 1) return {A[0] * B[0]};int mid = n / 2;// 分割多项式vector<int> A0(A.begin(), A.begin() + mid); // [0, mid - 1)vector<int> A1(A.begin() + mid, A.end()); //vector<int> B0(B.begin(), B.begin() + mid);vector<int> B1(B.begin() + mid, B.end());// 递归计算vector<int> U = DC_multiplyPoly(A0, B0);vector<int> V = DC_multiplyPoly(A0, B1);vector<int> W = DC_multiplyPoly(A1, B0);vector<int> Z = DC_multiplyPoly(A1, B1);// 假设P0 = V(x) + W(x)vector<int> P0 = addPoly(V, W);// 合并结果vector<int> result(2 * n, 0);for (int i = 0; i < U.size(); i ++ ) result[i] += U[i];for (int i = 0; i < P0.size(); i ++ ) result[i + mid] += P0[i];for (int i = 0; i < Z.size(); i ++ ) result[i + 2 * mid] += Z[i];return result;
}
时间复杂度:O(n2)O(n^2)O(n2)
假设 n=2hn=2^hn=2h 且 T(1)=O(1)T(1)=O(1)T(1)=O(1),T(n)T(n)T(n) 是执行一次两个多项式均为 nnn 次的DC_multiplyPoly所需的时间。
vector<int> U = DC_multiplyPoly(A0, B0):T(n2)T(\frac{n}{2})T(2n)vector<int> V = DC_multiplyPoly(A0, B1):T(n2)T(\frac{n}{2})T(2n)vector<int> W = DC_multiplyPoly(A1, B0):T(n2)T(\frac{n}{2})T(2n)vector<int> Z = DC_multiplyPoly(A1, B1):T(n2)T(\frac{n}{2})T(2n)vector<int> P0 = addPoly(V, W):O(n)O(n)O(n)- …
for (int i = 0; i < Z.size(); i ++ ) result[i + 2 * mid] += Z[i]:O(n)O(n)O(n)vector<int> A0(A.begin(), A.begin() + mid):O(1)O(1)O(1)- …
vector<int> B1(B.begin() + mid, B.end()):O(1)O(1)O(1)
Tn=4T(n2)+cn+O(n)=4[4T(n22)+cn2+O(n2)]+cn+O(n)=42T(n22)+(1+2)cn+O(n)=42[4T(n23)+cn22+O(n22)]+(1+2)cn+O(n)=43T(n23)+(1+2+22)cn+O(n)=...=4iT(n2i)+∑j=0i−12jcn+O(n)=...=4hT(n2h)+∑j=0h−12jcn+O(n)=(2h)2T(1)+1⋅(1−2h)1−2cn+O(n)=n2T(1)+cn(n−1)+O(n)=O(n2)+cn2−cn+O(n)=O(n2)\begin{aligned} T_n&=4T(\frac{n}{2})+cn+O(n) \\&= 4\left[4T\left(\frac{n}{2^2}\right)+c\frac{n}{2}+O(\frac{n}{2})\right]+cn+O(n) \\ & = 4^2T\left(\frac{n}{2^2}\right)+(1+2)cn +O(n) \\ & =4^2\left[4T\left(\frac{n}{2^3}\right)+c\frac{n}{2^2} + O(\frac{n}{2^2})\right]+(1+2)cn+O(n) \\ & = 4^3T\left(\frac{n}{2^3}\right)+(1+2+2^2)cn + O(n) \\ &= ... \\& = 4^iT\left(\frac{n}{2^i}\right)+\sum_{j=0}^{i-1}2^jcn +O(n) \\&= ... \\& = 4^hT\left(\frac{n}{2^h}\right)+\sum_{j=0}^{h-1}2^jcn +O(n) \\&= (2^h)^2T(1)+\frac{1\cdot(1-2^h)}{1-2}cn + O(n) \\&=n^2T(1)+cn(n-1) + O(n) \\&= O(n^2)+cn^2-cn+O(n) \\&=O(n^2) \end{aligned}Tn=4T(2n)+cn+O(n)=4[4T(22n)+c2n+O(2n)]+cn+O(n)=42T(22n)+(1+2)cn+O(n)=42[4T(23n)+c22n+O(22n)]+(1+2)cn+O(n)=43T(23n)+(1+2+22)cn+O(n)=...=4iT(2in)+j=0∑i−12jcn+O(n)=...=4hT(2hn)+j=0∑h−12jcn+O(n)=(2h)2T(1)+1−21⋅(1−2h)cn+O(n)=n2T(1)+cn(n−1)+O(n)=O(n2)+cn2−cn+O(n)=O(n2)
Karatsuba(优化的分治算法)
由上述的基础分治算法可以知道 A(x)B(x)A(x)B(x)A(x)B(x) 多项式乘积的形式为:
A(x)B(x)=A0(x)B0(x)+[A0(x)B1(x)+A1(x)B0(x)]xn2+A1(x)B1(x)x2⌊n2⌋A(x)B(x)=A_{0}(x)B_{0}(x)+[A_{0}(x)B_{1}(x) + A_{1}(x)B_{0}(x)]x^{\frac{n}{2}}+A_{1}(x)B_{1}(x)x^{2\lfloor\frac{n}{2}\rfloor}A(x)B(x)=A0(x)B0(x)+[A0(x)B1(x)+A1(x)B0(x)]x2n+A1(x)B1(x)x2⌊2n⌋
我们在基础的分治算法的基础上,重新定义:
Y(x)=[A0(x)+A1(x)]×[B0(x)+B1(x)]U(x)=A0(x)B0(x)Z(x)=A1(x)B1(x)\begin{aligned}Y(x)&=[A_0(x)+A_1(x)]\times[B_0(x)+B_1(x)]\\U(x)&=A_0(x)B_0(x)\\Z(x)&=A_1(x)B_1(x)\end{aligned}Y(x)U(x)Z(x)=[A0(x)+A1(x)]×[B0(x)+B1(x)]=A0(x)B0(x)=A1(x)B1(x)
故有
A0(x)B1(x)+A1(x)B0(x)=Y(x)−U(x)−Z(x)A_{0}(x)B_{1}(x) + A_{1}(x)B_{0}(x)=Y(x)-U(x)-Z(x)A0(x)B1(x)+A1(x)B0(x)=Y(x)−U(x)−Z(x)
即最后 A(x)B(x)A(x)B(x)A(x)B(x) 的多项式为:
A(x)B(x)=U(x)+[Y(x)−U(x)−Z(x)]x⌊n2⌋+Z(x)×x2⌊n2⌋A(x)B(x)=U(x)+[Y(x)-U(x)-Z(x)]x^{\lfloor\frac{n}{2}\rfloor}+Z(x)\times x^{2\lfloor\frac{n}{2}\rfloor}A(x)B(x)=U(x)+[Y(x)−U(x)−Z(x)]x⌊2n⌋+Z(x)×x2⌊2n⌋
我们用了一个小的数学技巧,将原本需要分割成 4 个 n2\frac{n}{2}2n 的子问题,变成了 3 个 n2\frac{n}{2}2n 个子问题。
// 多项式相减 A - B
vector<int> subPoly(const vector<int>& A, const vector<int>& B) {int n = max(A.size(), B.size());vector<int> result(n, 0);for (int i = 0; i < n; i++) {if (i < A.size()) result[i] += A[i];if (i < B.size()) result[i] -= B[i];}return result;
}vector<int> Karatsuba_multiplyPoly(const vector<int>& A, const vector<int>& B) {int n = A.size();// 基本情况if (A.empty() || B.empty()) return {};if (n == 1) return {A[0] * B[0]};int mid = n / 2;// 分割多项式vector<int> A0(A.begin(), A.begin() + mid); // [0, mid - 1)vector<int> A1(A.begin() + mid, A.end()); //vector<int> B0(B.begin(), B.begin() + mid);vector<int> B1(B.begin() + mid, B.end());// 递归计算 修改点在这里!!!!vector<int> U = Karatsuba_multiplyPoly(A0, B0);vector<int> Z = Karatsuba_multiplyPoly(A1, B1);vector<int> Y = Karatsuba_multiplyPoly(addPoly(A0, A1), addPoly(B0, B1));// 假设P0 = Y(x) - U(x) - Z(x)P0 = subPoly(subPoly(Y, U), Z);// 合并结果vector<int> result(2 * n, 0);for (int i = 0; i < U.size(); i ++ ) result[i] += U[i];for (int i = 0; i < P0.size(); i ++ ) result[i + mid] += P0[i];for (int i = 0; i < Z.size(); i ++ ) result[i + 2 * mid] += Z[i];return result;
}
时间复杂度:O(nlog23)≈O(n1.585)O(n^{\log_23})\approx O(n^{1.585})O(nlog23)≈O(n1.585)
假设 n=2hn=2^hn=2h 且 T(1)=O(1)T(1)=O(1)T(1)=O(1),T(n)T(n)T(n) 是执行一次两个多项式均为 nnn 次的Karatsuba_multiplyPoly所需的时间。
vector<int> U = DC_multiplyPoly(A0, B0):T(n2)T(\frac{n}{2})T(2n)vector<int> Z = DC_multiplyPoly(A1, B1):T(n2)T(\frac{n}{2})T(2n)vector<int> Y = Karatsuba_multiplyPoly(addPoly(A0, A1), addPoly(B0, B1)):T(n2)T(\frac{n}{2})T(2n)addPoly(V, W):O(n)O(n)O(n)subPoly(V, W):O(n)O(n)O(n)- …
for (int i = 0; i < Z.size(); i ++ ) result[i + 2 * mid] += Z[i]:O(n)O(n)O(n)vector<int> A0(A.begin(), A.begin() + mid):O(1)O(1)O(1)- …
vector<int> B1(B.begin() + mid, B.end()):O(1)O(1)O(1)
Tn=3T(n2)+cn+O(n)=3[3T(n22)+cn2+O(n2)]+cn+O(n)=32T(n22)+(1+32)cn+O(n)=32[3T(n23)+cn22+O(n22)]+(1+32)cn+O(n)=33T(n23)+(1+32+[32]2)cn+O(n)=...=3hT(n2h)+∑j=0h−1[32]jcn+O(n)=3hT(1)+c2(3h−n)+O(n)=(2log23)hT(1)+c2((2log23)h−n)+O(n)=2hlog23T(1)+c2(2hlog23−n)+O(n)=(2h)log23T(1)+c2((2h)log23−n)+O(n)=O(nlog23)+c2(nlog23−n)+O(n)=O(nlog23)\begin{aligned} T_n&=3T(\frac{n}{2})+cn+O(n) \\&= 3\left[3T\left(\frac{n}{2^2}\right)+c\frac{n}{2}+O(\frac{n}{2})\right]+cn+O(n) \\ & = 3^2T\left(\frac{n}{2^2}\right)+(1+\frac{3}{2})cn +O(n) \\ & =3^2\left[3T\left(\frac{n}{2^3}\right)+c\frac{n}{2^2} + O(\frac{n}{2^2})\right]+(1+\frac{3}{2})cn+O(n) \\ & = 3^3T\left(\frac{n}{2^3}\right)+(1+\frac{3}{2}+[\frac{3}{2}]^2)cn + O(n) \\ &= ... \\& = 3^hT\left(\frac{n}{2^h}\right)+\sum_{j=0}^{h-1}[\frac{3}{2}]^jcn +O(n) \\& = 3^hT(1)+\frac{c}{2}(3^{h}-n) + O(n) \\& = (2^{\log_2 3})^hT(1)+\frac{c}{2}((2^{\log_2 3})^h-n) + O(n) \\& = 2^{h\log_2 3}T(1)+\frac{c}{2}(2^{h\log_2 3}-n) + O(n) \\& = (2^h)^{{\log_2 3}}T(1)+\frac{c}{2}((2^h)^{{\log_2 3}}-n) + O(n) \\&=O(n^{\log_23})+\frac{c}{2}(n^{\log_23}-n) + O(n) \\&=O(n^{\log_23}) \end{aligned}Tn=3T(2n)+cn+O(n)=3[3T(22n)+c2n+O(2n)]+cn+O(n)=32T(22n)+(1+23)cn+O(n)=32[3T(23n)+c22n+O(22n)]+(1+23)cn+O(n)=33T(23n)+(1+23+[23]2)cn+O(n)=...=3hT(2hn)+j=0∑h−1[23]jcn+O(n)=3hT(1)+2c(3h−n)+O(n)=(2log23)hT(1)+2c((2log23)h−n)+O(n)=2hlog23T(1)+2c(2hlog23−n)+O(n)=(2h)log23T(1)+2c((2h)log23−n)+O(n)=O(nlog23)+2c(nlog23−n)+O(n)=O(nlog23)
