由于在第三十一章数论算法中遇到几个关于超大数乘法的问题促使我需要学这章,具体请看第三十一章练习31.1-8,31.1-12与31.1-13.
基本概念:
大整数的加减乘除
系数形式表示的多项式的快速乘法
1.两个n次多项式a与b分别计算在2n次单位复数根下的对应多项式值。计算过程使用的是FFT。所以时间为O(nlgn)
2.随后进行点值乘法,根据c(w0)=a(w0)*b(w0)在n次单位复数根下的对应的多项式值c(w0),那么记录点c(w0,c(w0)) 以此类推,记录一系列C=(c0,c1....cn).,其时间为O(n)
3.把一系列C在单位复数根下的点值表达通过DFT逆计算方式转换成多项式C的系数表达,由此求得结果。其时间为O(nlgn),所以总的运行时间是O(nlgn)+O(nlgn)+O(n)=O(nlgn)
30.1-1 运用等式(30,1)和(30.2)把下列两个多项式相乘:A(x)=7x^3-x^2+x-10 B(x)=8x^3-6x+3
由于过于简单,直接上结果了。C(x)=56x^6-8x^5-34x^4-53x^3-9x^2+63x-30.
30.1-2 求一个次数界为n的多项式A(x)在某给定点x0的值存在另外一种方法;把多项式A(x)除以多项式(x-x0),得到一个次数界为n-1的商多项式q(x)和余项r,满足A(x)=q(x)(x-x0)+r.很明显,A(x0)=r.请说明如何根据x0和A的系数,在O(n)的时间复杂度内计算出余项r以及q(x)的系数。
//30.1-2另类的计算多项式在某点值方法 #include <iostream> #include <vector> using namespace std; struct Polynomial { int coef;//系数 int Index;//指数 }; int Division_with_remainder(vector<Polynomial>a,vector<Polynomial>&qx,int x0,const int n) { // vector<Polynomial>temp; int temp=0,i=0,s=1,k=a[n-1].Index; Polynomial q; if (n==1)//如果就一项,那么直接求值即可 { i=a[0].Index; q.coef=-a[0].coef; q.Index=a[0].Index; qx.push_back(q); while (i) { s*=x0; i--; } return s*a[0].coef; } else//如果多余2项,那么用类似小学的除法式子去除 { while(k>=1) { q.coef=-a[k].coef*x0; cout<<q.coef<<endl; a[k-1].coef=a[k-1].coef-a[k].coef*x0; q.Index=a[k-1].Index; qx.push_back(q); k--; } return a[k].coef; } } void main() { cout<<"请输入需要在哪个点求值:"<<endl; int x0,i=0; cin>>x0;//由于程序并不非常强壮,所以请不要输入字符或者直接输入ctrl+z,只能输入一些整数。输入系数时也是一样的。 cout<<"请按由低次到高次依次输入每项系数,且每项次数均不同(注意系数为0的项不能省略输入,直接补0):"<<endl; vector<Polynomial>a,qx;//a表示多项式系数向量。 struct Polynomial x; while (cin>>x.coef)//输入多项式系数,从低次项到高次项依次输入,输入ctrl+z结束输入。 { x.Index=i; a.push_back(x); i++; } const int n=i; cout<<"您输入的多项式为:"<<endl; while (i) { if(i==1)cout<<a[i-1].coef<<"x^"<<a[i-1].Index; else cout<<a[i-1].coef<<"x^"<<a[i-1].Index<<"+"; i--; } cout<<endl; cout<<"多项式在点"<<x0<<"的值为:"<<Division_with_remainder(a,qx,-x0,n)<<endl; int k=0; cout<<"多项式的商q(x)="; while (k!=n-1) { if(k==n-2)cout<<qx[k].coef<<"x^"<<qx[k].Index<<endl; else cout<<qx[k].coef<<"x^"<<qx[k].Index<<"+"; k++; } }
30.1-3从A(x)=∑ajx^j的点值表达推导出A^res(x)=∑a(n-1-j)x^j(res是将多项式系数逆转)的点值表达,假设没有一个点是0。
这里简要的说明下思路:先用DFT逆求出A(x)在单位根下的系数表达,然后逆转系数(倒序)再次用FFT求出逆转多项式在单位根下的点值表达。运行时间为O(nlgn).
30.1-4证明:为了唯一确定一个次数界为n的多项式,n个相互不同的点值对是必须的。也就是说,如果给定少于n个不同点值对,则他们不能唯一确定一个次数界为n的多项式。(提示:利用定理30.1,加入一个任意选择的点值对到一个已有n-1个点值对的集合,看看会发生什么?)
如果少于n个不同点值对,那么这n个点里必有相同的点使:xi=xj,那么范德蒙德矩阵的行列式=0=>矩阵是不可逆的=>
所以不能通过矩阵方程确定唯一的系数向量a,得出结论。
30.1-5 说明如何利用等式(30.5)在O(n^2)时间复杂度内进行插值运算。(提示:首先计算多项式π(x-xj)的系数表达,然后把每个项除以(x-xk);参见练习30.1.2.你可以在O(n)时间内计算n个分母的每一个。)
这里就说下思路:假设已知n个点(x0,y0),(x1,y1)...(xn,yn).
1.将n个单位复数根依次带入π(x-xj)得出n个多项式值yi,这个过程为O(n^2).
2.然后利用DFT逆求出它的系数表达,这个过程需要O(nlgn).
3.然后再写一个求yk/π(xj-xk)的循环,这个循环大约O(n^2),把每个求得的值存放在数组a中.
4.于是利用练习30.1-2,对这个求出系数的多项式依次除以(x-xj)并且乘以a[i],每次做多项式除法需要O(n)时间,然后同时循环n次求累加和,最终这个双重循环需要O(n^2).
最后计算总的运行时间为T(n)=O(n^2)+O(nlgn)+O(n^2)+O(n^2)=O(n^2).
30.1-6 此题没有思路。网上也没找到答案。这道题主要讨论的是多项式的(非)确定性。
30.1-7考虑两个集合A和B,每个集合包含取值范围在0~10n之间的n个整数。我们希望计算出A与B的笛卡尔和,定义如下:C={x+y:x∈A,y∈B}注意到,C中整数值的范围在0~20n之间。我们希望找到C中的元素,并且求出C中的每个元素可表示为A中元素与B中元素和的次数。请在O(nlgn)时间内解决问题.(提示:请用次数至多是10n的多项式来表示A和B)。
多项式A与B是系数均为1的,指数为0~10n之间的n个整数.计算C(x)=A(x)*B(x)可以用DFT在O(nlgn)时间内计算出。然后再遍历一下C,C的系数就是A与B的笛卡尔和项的出现次数
30.2 DFT与FFT
单位复数根:n次单位复数根是满足w^n=1的复数w. 复数的指数形式定义:e^iu=cos(u)+isin(u).
n次单位复数根:wn=e^(2πi/n)。
30.3消去引理: 对任何整数n≥0,k≥0,以及d>0, w(dn,dk)=w(n,k)//w的第一个参数是下标,第二个参数是次数。
推论30.4 对任意偶数n>0,有w(n,n/2)=w(2,1)=-1.
引理30.5折半引理:如果n>0为偶数,那么n个n次单位复数数根的平方的集合就是n/2个n/2次单位复数根的集合。
引理30.6求和引理:对任意整数n≥1和不能被n整除的非负整数k,有∑(w(n,k)^j)=0
DFT:就是求在单位复数根处的多项式的值。
FFT:就是在O(nlgn)时间内计算出DFT(a).
DFT逆:就是把书上伪代码a与y互换,wn^-1替换wn,并将结果÷n即可求得答案。
书上伪代码翻译成C++程序如下:
#include <iostream> #include <stdio.h> #include <math.h> #include <vector> using namespace std; #define pi 3.1415926535 int m=0; struct Complex { double real; double imag; int num; Complex(int i=0,int j=0){real=i,imag=j;} }; Complex q(1,0); Complex operator+ (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real =lhs.real+rhs.real; temp.imag = lhs.imag+ rhs.imag; return temp; } Complex operator- (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real - rhs.real; temp.imag = lhs.imag - rhs.imag; return temp; } Complex operator* (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real * rhs.real - lhs.imag * rhs.imag; temp.imag= lhs.real * rhs.imag + lhs.imag * rhs.real; return temp; } Complex operator* ( const int &lhs, Complex const & rhs) { Complex temp; temp.real=lhs*rhs.real; temp.imag=lhs*rhs.imag; return temp; } istream &operator>>(istream&is, Complex &item) { is >> item.real>>item.imag; return is; } vector<Complex> recursive_FFT(vector<Complex> const&a) { size_t n = a.size(); if (n == 1) return a; struct Complex wn, w; wn.real = cos(2 * pi / n), wn.imag = sin(2 * pi / n); w.real = 1, w.imag = 0; vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++) { a0.push_back(a[i * 2]); a1.push_back(a[i * 2 + 1]); } vector<Complex>y0 = recursive_FFT(a0); vector<Complex>y1 = recursive_FFT(a1); vector<Complex>y; y.resize(n); for (int k = 0; k<n / 2; k++) { y[k] = y0[k] + w*y1[k]; y[k + n / 2] = y0[k] - w*y1[k]; w = w*wn; } return y; } void main() { cout << "请输入需要计算的多项式最高次数,注意必须是3的幂" << endl; int j = 0; cin >> j; const int n = j; vector<Complex>a; cout << "请输入多项式各项系数:"; double k = 0; Complex i; while (k != n&&cin >> i) { a.push_back(i); k++; } vector<Complex>y = recursive_FFT(a); for (int t = 0; t<y.size(); t++) { printf("%g", y[t].real);//求DFT逆需要把结果÷n if (fabs(y[t].imag) < 0.001)//虚数小于0.001,那么虚数忽略不计 { cout << endl; continue; } else { if (y[t].imag<0) printf("%gi", y[t].imag); else printf("+%gi", y[t].imag); } cout << endl; } }
30.2-1证明推论30.4.
30.2-2 计算向量(0,1,2,3)的DFT。
30.2-3采用运行时间为O(nlgn)的方案完成练习30.1-1
代码如下:
<span style="color:#000000;">#include <iostream> #include <stdio.h> #include <math.h> #include <vector> using namespace std; #define pi 3.1415926535 struct Complex { double real; double imag; int num; Complex(int i=0,int j=0){real=i,imag=j;} }; Complex q(1,0); Complex operator+ (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real =lhs.real+rhs.real; temp.imag = lhs.imag+ rhs.imag; return temp; } Complex operator- (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real - rhs.real; temp.imag = lhs.imag - rhs.imag; return temp; } Complex operator* (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real * rhs.real - lhs.imag * rhs.imag; temp.imag= lhs.real * rhs.imag + lhs.imag * rhs.real; return temp; } Complex operator* ( const int &lhs, Complex const & rhs) { Complex temp; temp.real=lhs*rhs.real; temp.imag=lhs*rhs.imag; return temp; } vector<Complex> operator* (vector<Complex>const&a,vector<Complex>const&b) { vector<Complex> temp; for (size_t i=0;i<a.size();i++) { temp.push_back(a[i]*b[i]); } return temp; } istream &operator>>(istream&is, Complex &item) { is >> item.real>>item.imag; return is; } vector<Complex> recursive_FFT(vector<Complex> const&a) { size_t n = a.size();//有改动 if (n == 1) return a; struct Complex wn, w; wn.real = cos(2 * pi / n), wn.imag = sin(2 * pi / n); w.real = 1, w.imag = 0; vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++) { a0.push_back(a[i * 2]); a1.push_back(a[i * 2 + 1]); } vector<Complex>y0 = recursive_FFT(a0); vector<Complex>y1 = recursive_FFT(a1); vector<Complex>y; y.resize(n); for (int k = 0; k<n / 2; k++) { y[k] = y0[k] + w*y1[k]; y[k + n / 2] = y0[k] - w*y1[k]; w = w*wn; } return y; } vector<Complex> recursive_FFT_opposite(vector<Complex> const&a) { size_t n = a.size(); if (n == 1) { return a; } struct Complex wn, w; wn.real = cos(-2 * pi / n), wn.imag = sin(-2 * pi / n);// 注意求DFT的逆是负数的 w.real = 1, w.imag = 0; vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++) { a0.push_back(a[i * 2]); a1.push_back(a[i * 2 + 1]); } vector<Complex>y0 = recursive_FFT_opposite(a0); vector<Complex>y1 = recursive_FFT_opposite(a1); vector<Complex>y; y.resize(n); for (int k = 0; k<n / 2; k++) { y[k] = y0[k] + w*y1[k]; y[k + n / 2] = y0[k] - w*y1[k]; w = w*wn; } return y; } vector<Complex> Polynomial_multiplication(vector<Complex> const&a,vector<Complex> const&b) { vector<Complex>ya=recursive_FFT(a); vector<Complex>yb=recursive_FFT(b); vector<Complex>yc=ya*yb; vector<Complex>temp=recursive_FFT_opposite(yc); return temp; } void main() { cout << "请输入需要计算的多项式最高次数,注意必须是2的幂" << endl; int j = 0; cin >> j; const int n = j; vector<Complex>a,b; cout << "请输入多项式A各项系数(注意系数为0的项要补0):"; int k1 = 0,k2=0; Complex i1,i2; while (k1 != n&&cin >> i1) { //x.push_back(i); a.push_back(i1); k1++; } cout << "请输入多项式B各项系数(注意系数为0的项要补0):"; while (k2 != n&&cin >> i2) { b.push_back(i2); k2++; } vector<Complex>y = Polynomial_multiplication(a,b); for (int t = 0; t<y.size(); t++) { printf("%g ", y[t].real/n);//求DFT逆需要把结果÷n if (fabs(y[t].imag) < 0.001)//虚数小于0.001,那么虚数忽略不计 { continue; } else { if (y[t].imag<0) printf("%gi", y[t].imag/n); else printf("+%gi", y[t].imag/n); } } }</span>
结果图:
30.2-4 写出伪代码,在O(nlgn)运行时间内计算出DFT^-1.
<span style="color:#000000;">#include <iostream> #include <stdio.h> #include <math.h> #include <vector> using namespace std; #define pi 3.1415926535 struct Complex { double real; double imag; int num; Complex(int i=0,int j=0){real=i,imag=j;} }; Complex q(1,0); Complex operator+ (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real =lhs.real+rhs.real; temp.imag = lhs.imag+ rhs.imag; return temp; } Complex operator- (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real - rhs.real; temp.imag = lhs.imag - rhs.imag; return temp; } Complex operator* (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real * rhs.real - lhs.imag * rhs.imag; temp.imag= lhs.real * rhs.imag + lhs.imag * rhs.real; return temp; } Complex operator* ( const int &lhs, Complex const & rhs) { Complex temp; temp.real=lhs*rhs.real; temp.imag=lhs*rhs.imag; return temp; } istream &operator>>(istream&is, Complex &item) { is >> item.real>>item.imag; return is; } vector<Complex> recursive_FFT_opposite(vector<Complex> const&a) { size_t n = a.size(); if (n == 1) return a; struct Complex wn, w; wn.real = cos(-2 * pi / n), wn.imag = sin(-2 * pi / n); w.real = 1, w.imag = 0; vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++) { a0.push_back(a[i * 2]); a1.push_back(a[i * 2 + 1]); } vector<Complex>y0 = recursive_FFT_opposite(a0); vector<Complex>y1 = recursive_FFT_opposite(a1); vector<Complex>y; y.resize(n); for (int k = 0; k<n / 2; k++) { y[k] = y0[k] + w*y1[k]; y[k + n / 2] = y0[k] - w*y1[k]; w = w*wn; } return y; } void main() { cout << "请输入需要计算的多项式最高次数,注意必须是2的幂" << endl; int j = 0; cin >> j; const int n = j; vector<Complex>a; cout << "请输入多项式A各项系数(注意系数为0的项要补0):"; int k = 0; Complex i; while (k != n&&cin >> i) { a.push_back(i); k++; } vector<Complex>y = recursive_FFT_opposite(a); for (int t = 0; t<y.size(); t++) { printf("%g ", y[t].real/n);//求DFT逆需要把结果÷n if (fabs(y[t].imag) < 0.001)//虚数小于0.001,那么虚数忽略不计 { cout << endl; continue; } else { if (y[t].imag<0) printf("%gi", y[t].imag/n); else printf("+%gi", y[t].imag/n); } cout << endl; } }</span>
30.2-5请把FFT推广到n是3的幂的情形,写出运行时间的递归式并求解。
代码如下:
<span style="color:#000000;">#include <iostream> #include <stdio.h> #include <math.h> #include <vector> using namespace std; #define pi 3.1415926535 struct Complex { double real; double imag; int num; Complex(int i=0,int j=0){real=i,imag=j;} }; Complex q(1,0); Complex operator+ (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real =lhs.real+rhs.real; temp.imag = lhs.imag+ rhs.imag; return temp; } Complex operator- (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real - rhs.real; temp.imag = lhs.imag - rhs.imag; return temp; } Complex operator* (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real * rhs.real - lhs.imag * rhs.imag; temp.imag= lhs.real * rhs.imag + lhs.imag * rhs.real; return temp; } Complex operator* ( const int &lhs, Complex const & rhs) { Complex temp; temp.real=lhs*rhs.real; temp.imag=lhs*rhs.imag; return temp; } istream &operator>>(istream&is, Complex &item) { is >> item.real>>item.imag; return is; } vector<Complex> recursive_FFT_3(vector<Complex> const&a) { size_t n = a.size(); if (n == 1) return a; struct Complex wn, w,w1,w2; wn.real = cos(2 * pi / n), wn.imag = sin(2 * pi / n);//如果求逆需要取负度数 w.real = 1, w.imag = 0; vector<Complex>a0,a1,a2; a0.reserve(n/3); a1.reserve(n/3); a2.reserve(n/3); for (int i = 0; i<n/3; i++) { a0.push_back(a[i * 3]); a1.push_back(a[i * 3 + 1]); a2.push_back(a[i * 3 + 2]); } vector<Complex>y0 = recursive_FFT_3(a0); vector<Complex>y1 = recursive_FFT_3(a1); vector<Complex>y2 = recursive_FFT_3(a2); vector<Complex>y; y.resize(n); w1.real=cos(2 * pi / 3),w1.imag=sin(2 * pi /3); w2.real=cos(4 * pi / 3),w2.imag=sin(4 * pi /3); for (int k = 0; k<n / 3; k++) { y[k] = y0[k] + w*y1[k] + w*w*y2[k]; y[k + n / 3] = y0[k] + w*w1*y1[k] + w*w*w1*w1*y2[k]; y[k + 2*n / 3] = y0[k] + w*w2*y1[k] + w*w*w2*w2*y2[k]; w = w*wn; } return y; } void main() { cout << "请输入需要计算的多项式最高次数,注意必须是3的幂" << endl; int j = 0; cin >> j; const int n = j; vector<Complex>a,b; cout << "请输入多项式A各项系数(注意系数为0的项要补0):"; int k1 = 0,k2=0; Complex i1,i2; while (k1 != n&&cin >> i1) { //x.push_back(i); a.push_back(i1); k1++; } vector<Complex>y = recursive_FFT_3(a); for (int t = 0; t<y.size(); t++) { printf("%g ", y[t].real);//求DFT逆需要把结果÷n if (fabs(y[t].imag) < 0.001)//虚数小于0.001,那么虚数忽略不计 { cout << endl; continue; } else { if (y[t].imag<0) printf("%gi", y[t].imag); else printf("+%gi", y[t].imag); } cout << endl; } }</span>
其递归时间为T(n)=3T(n/3)+O(n)=>T(n)=O(nlgn),所以和基2FFT的复杂度是一样的。
30.2-6略。主要是不太理解”完备的“是什么意思?
30.2-7给定一组值z0,z1...zn-1(可能重复),说明如何求出仅以z0,z1...zn-1(可能有重复)为零点的一个次数界为n+1的多项式P(x)的系数。你给出的过程运行时间为O(nlgnlgn).(提示:当仅当P(x)在zj处值为0)
由提示可得:P(x)=(x-z0)(x-z1)...(x-zn-1) 将n次单位复数根依次带入多项式,得到向量y=(y1,y2..yn-1)。然后可以用DFT逆求出独享式P(x)的系数。具体看下面代码:
//30.2-7这个版本的时间复杂度是O(nlgnlgn) #include <iostream> #include <stdio.h> #include <math.h> #include <vector> using namespace std; #define pi 3.1415926535 #define nn 8 //输入你想要计算的项数,记住一定要2的幂额 struct Complex { double real; double imag; int num; Complex(int i=0,int j=0){real=i,imag=j;} }; Complex q(1,0); Complex operator+ (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real =lhs.real+rhs.real; temp.imag = lhs.imag+ rhs.imag; return temp; } Complex operator- (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real - rhs.real; temp.imag = lhs.imag - rhs.imag; return temp; } Complex operator* (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real * rhs.real - lhs.imag * rhs.imag; temp.imag= lhs.real * rhs.imag + lhs.imag * rhs.real; return temp; } Complex operator* ( const int &lhs, Complex const & rhs) { Complex temp; temp.real=lhs*rhs.real; temp.imag=lhs*rhs.imag; return temp; } vector<Complex> operator* (vector<Complex>const&a,vector<Complex>const&b) { Complex y; vector<Complex> temp(a.size(),y); for (size_t i=0;i<a.size();i++) { temp[i]=a[i]*b[i]; } return temp; } Complex operator/(Complex &a,double b) { Complex temp; temp.real=a.real/b; temp.imag=a.imag/b; return temp; } vector<Complex> operator/(vector<Complex>&a,double b) { vector<Complex>temp(a.size(),0); for (size_t i=0;i<a.size();i++) { temp[i]=a[i]/b; } return temp; } istream &operator>>(istream&is, Complex &item) { is >> item.real>>item.imag; return is; } vector<Complex> recursive_FFT(vector<Complex> const&a) { size_t n = a.size();//有改动 if (n == 1) return a; struct Complex wn, w; wn.real = cos(2 * pi / n), wn.imag = sin(2 * pi / n); w.real = 1, w.imag = 0; vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++) { a0.push_back(a[i * 2]); a1.push_back(a[i * 2 + 1]); } vector<Complex>y0 = recursive_FFT(a0); vector<Complex>y1 = recursive_FFT(a1); vector<Complex>y; y.resize(n); for (int k = 0; k<n / 2; k++) { y[k] = y0[k] + w*y1[k]; y[k + n / 2] = y0[k] - w*y1[k]; w = w*wn; } return y; } vector<Complex> recursive_FFT_opposite(vector<Complex> const&a) { size_t n = a.size(); if (n == 1) { return a; } struct Complex wn, w; wn.real = cos(-2 * pi / n), wn.imag = sin(-2 * pi / n);// 注意求DFT的逆是负数的 w.real = 1, w.imag = 0; vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++) { a0.push_back(a[i * 2]); a1.push_back(a[i * 2 + 1]); } vector<Complex>y0 = recursive_FFT_opposite(a0); vector<Complex>y1 = recursive_FFT_opposite(a1); vector<Complex>y; y.resize(n); for (int k = 0; k<n / 2; k++) { y[k] = y0[k] + w*y1[k]; y[k + n / 2] = y0[k] - w*y1[k]; w = w*wn; } return y; } vector<Complex> Polynomial_multiplication(vector<Complex> &a,vector<Complex> &b) { Complex y; int i=0; int t=a.size(); while (i!=t) { a.push_back(y); b.push_back(y); i++; } vector<Complex>ya=recursive_FFT(a); vector<Complex>yb=recursive_FFT(b); vector<Complex>yc=ya*yb; vector<Complex>temp=recursive_FFT_opposite(yc);//应用卷积定理 return temp; } vector<Complex> Polynomial_0(vector<Complex> const&a)//求(x-z1)(x-z2)..(x-zn)的主函数 { size_t n=a.size(); if (n==2)//n=2时,可以得到系数向量f(x)=x^2-(z1+z2)x+z1*z2 { Complex y1(1,0),y2(a[1].real+a[0].real,0),y3(a[1].real*a[0].real,0),y4; vector<Complex>yy(4,y4); yy[0]=y1; yy[1]=y2; yy[2]=y3; return yy; } vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++)//前后各一半分配给a0与a1 { a0.push_back(a[i ]); a1.push_back(a[i +n/2]); } vector<Complex>y0=Polynomial_0(a0);//分治法分成前一半T(n/2) vector<Complex>y1=Polynomial_0(a1);//分治法分成后一半T(n/2) vector<Complex>y; y.resize(n); y=Polynomial_multiplication(y0,y1);//多项式乘法O(nlgn) y=y/(2*n); return y;//T(n)=2T(n/2)+O(nlgn) } void main() { vector<Complex>a; cout << "请输入多项式A各项系数(注意系数为0的项要补0):"; int k1 = 0,k2=0; Complex i; while (k1 != nn&&cin >> i) { a.push_back(i); k1++; } while (--k1) { if (a[k1].real!=0||a[k1].imag!=0) { break; } k1--; } vector<Complex>y = Polynomial_0(a); for (int t = 0; t<=k1+1; t++) { printf("%g ", y[t].real);//求DFT逆需要把结果÷n if (fabs(y[t].imag) < 0.001)//虚数小于0.001,那么虚数忽略不计 { cout << endl; continue; } else { if (y[t].imag<0) printf("%gi", y[t].imag); else printf("+%gi", y[t].imag); } cout << endl; } }
上面这个版本的时间复杂度是O(nlgn) ,下面的版本是O(n^2)
<span style="color:#000000;">#include <iostream> #include <stdio.h> #include <math.h> #include <vector> using namespace std; #define pi 3.1415926535 int m=0; struct Complex { double real; double imag; int num; Complex(int i=0,int j=0){real=i,imag=j;} }; Complex q(1,0); Complex operator+ (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real =lhs.real+rhs.real; temp.imag = lhs.imag+ rhs.imag; return temp; } Complex operator- (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real - rhs.real; temp.imag = lhs.imag - rhs.imag; return temp; } Complex operator* (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real * rhs.real - lhs.imag * rhs.imag; temp.imag= lhs.real * rhs.imag + lhs.imag * rhs.real; return temp; } Complex operator* ( const int &lhs, Complex const & rhs) { Complex temp; temp.real=lhs*rhs.real; temp.imag=lhs*rhs.imag; return temp; } istream &operator>>(istream&is, Complex &item) { is >> item.real>>item.imag; return is; } vector<Complex> recursive_FFT_opposite(vector<Complex>const&a) { size_t n = a.size(); if (n == 1) { return a; } struct Complex wn, w; wn.real = cos(-2 * pi / n), wn.imag = sin(-2 * pi / n);// 注意求DFT的逆是负数的 w.real = 1, w.imag = 0; vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++) { a0.push_back(a[i * 2]); a1.push_back(a[i * 2 + 1]); } vector<Complex>y0 = recursive_FFT_opposite(a0); vector<Complex>y1 = recursive_FFT_opposite(a1); vector<Complex>y; y.resize(n); for (int k = 0; k<n / 2; k++) { y[k] = y0[k] + w*y1[k]; y[k + n / 2] = y0[k] - w*y1[k]; w = w*wn; } return y; } vector<Complex> recursive_FFT_opposite1(vector<Complex> const&x,int j) {//O(n^2) const int n = j; vector<Complex>a; int k=0; Complex i,wn,w; wn.real=cos(2*pi/n),wn.imag=sin(2*pi/n); w.real=1,w.imag=0; while (k != n)//O(n) {//O(n^2) m=0; q.real=1,q.imag=0; for (int t=0;t<n-1;t++)//O(n) { q=q*(w-x[t]); } a.push_back(q); w=w*wn; k++; } vector<Complex>y =recursive_FFT_opposite(a);//O(nlgn) return y; } void main() { cout << "请输入需要计算的多项式最高次数,注意必须是3的幂" << endl; int j = 0; cin >> j; const int n = j; vector<Complex>a,x; cout << "请输入多项式A各项系数(注意系数为0的项要补0):"; int k=0; Complex i,wn,w; wn.real=cos(2*pi/n),wn.imag=sin(2*pi/n); w.real=1,w.imag=0; while (k != n&&cin >> i) { x.push_back(i); //a.push_back(i1); k++; } vector<Complex>y = recursive_FFT_opposite1(x,j); for (int t = 0; t<y.size(); t++) { printf("%g ", y[t].real/n);//求DFT逆需要把结果÷n if (fabs(y[t].imag) < 0.001)//虚数小于0.001,那么虚数忽略不计 { cout << endl; continue; } else { if (y[t].imag<0) printf("%gi", y[t].imag/n); else printf("+%gi", y[t].imag/n); } cout << endl; } }</span>
//迭代的FFT,比递归的运行更快 #include <iostream> #include <math.h> #include <vector> using namespace std; #define pi 3.1415926535 struct Complex { double imag; double real; Complex(double r=0,double i=0){imag=i,real=r;} }; vector<Complex>a; Complex operator* (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real * rhs.real - lhs.imag * rhs.imag; temp.imag= lhs.real * rhs.imag + lhs.imag * rhs.real; return temp; } Complex operator+ (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real =lhs.real+rhs.real; temp.imag = lhs.imag+ rhs.imag; return temp; } Complex operator- (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real - rhs.real; temp.imag = lhs.imag - rhs.imag; return temp; } int rev(int k) { int temp=0,i=0; static int flag=0; size_t n=a.size()-1; if (!flag){while(n>>i)i++;flag=i;}//设置哨兵为了只调用一次这个循环 int j=flag; vector<int>b(n+1,0); while (j>0) { //b[--j]=(k-((k>>1)<<1)); b[--j]=k%2; k>>=1; temp+=b[j]<<j; } return temp; } vector<Complex> BIT_REVERSE_COPY(vector<Complex>&a,vector<Complex>&A) { size_t n=a.size(); for (size_t k=0;k<n;k++) { A[rev(k)]=a[k]; } return A; } int Log(int n)//由于n是2的幂,所以函数返回值一定是整数 { int temp=0; while (n>>=1) temp++; return temp; } vector<Complex> ITERATIVE_FFT(vector<Complex>&a,vector<Complex>&A) { BIT_REVERSE_COPY(a,A); size_t n=a.size(); for (int s=1;s<=Log(n);s++) { int m=pow(2,s); for (int k=0;k<=n-1;k+=m) { Complex w(1,0),wm(cos(2*pi/m),sin(2*pi/m)),t,u; for (int j=0;j<=m/2-1;j++) { t=w*A[k+j+m/2]; u=A[k+j]; A[k+j]=u+t; A[k+j+m/2]=u-t; w=w*wm; } } } return A; } void main() { Complex x,y; int i=0; while (cin>>x.real>>x.imag)//输入复系数 { a.push_back(x); i++; } vector<Complex>A(i,y); BIT_REVERSE_COPY(a,A); vector<Complex>yy = ITERATIVE_FFT(a,A); for (int t = 0; t<A.size(); t++) { printf("%g", A[t].real);//求DFT逆需要把结果÷n if (fabs(A[t].imag) < 0.001)//虚数小于0.001,那么虚数忽略不计 { cout << endl; continue; } else { if (A[t].imag<0) printf("%gi", A[t].imag); else printf("+%gi", A[t].imag); } cout << endl; } }
vector<Complex> ITERATIVE_FFT(vector<Complex>&a,vector<Complex>&A) { size_t n=a.size(); for (int s=1;s<=Log(n);s++) { int m=pow(2,s); for (int k=0;k<=n-1;k+=m) { Complex w(1,0),wm(cos(2*pi/m),sin(2*pi/m)),t,u; for (int j=0;j<=m/2-1;j++) { t=w*a[rev(k+j+m/2)]; u=a[rev(k+j)]; a[rev(k+j)]=u+t; a[rev(k+j+m/2)]=u-t; w=w*wm; } } } BIT_REVERSE_COPY(a, A); return A; }
vector<Complex> ITERATIVE_FFT(vector<Complex>&a,vector<Complex>&A) { BIT_REVERSE_COPY(a,A); size_t n=a.size(); for (int s=1;s<=Log(n);s++) { int m=pow(2,s); Complex w(1,0),wm(cos(2*pi/m),sin(2*pi/m)),t,u; for (int j=0;j<=m/2-1;j++) { for (int k=0;k<=n-1;k+=m) { t=w*A[k+j+m/2]; u=A[k+j]; A[k+j]=u+t; A[k+j+m/2]=u-t; } w=w*wm; } } return A; }
//O(n^lg3)的多项式乘法,这个多项式乘法递归函数总体来讲和书上的FFT结构类似 #include <iostream> #include <vector> #include <math.h> using namespace std; #define n 8 //n始终是2的幂,不满2的幂的多项式用0为系数的项自动补满使项数达到2的幂 struct Polynomial { int coef;//系数 int index;//指数 Polynomial(int c=0,int i=0){coef=c,index=i;}; }; Polynomial operator-(Polynomial&a,Polynomial&b)//运算符重载函数,下面几个函数类似。 { Polynomial temp; temp.coef=a.coef-b.coef; return temp; } vector<Polynomial> operator+(vector<Polynomial>&a,vector<Polynomial>&b) { vector<Polynomial>temp; temp.resize(a.size()); for (size_t i=0;i<a.size();i++) { temp[i].coef=a[i].coef+b[i].coef; temp[i].index=a[i].index; } return temp; } vector<Polynomial> operator-(vector<Polynomial>&a,vector<Polynomial>&b) { vector<Polynomial>temp; temp.resize(a.size()); for (size_t i=0;i<a.size();i++) { temp[i].coef=a[i].coef-b[i].coef; temp[i].index=a[i].index; } return temp; } Polynomial operator+(Polynomial&a,Polynomial&b) { Polynomial temp; temp.coef=a.coef+b.coef; return temp; } Polynomial operator*(Polynomial&a,Polynomial&b) { Polynomial temp; temp.coef=a.coef*b.coef; return temp; } vector<Polynomial> Polynomial_multiplication(vector<Polynomial>&a,vector<Polynomial>&b)//多项式乘法 {//T(n)=3T(n/2)+O(n) =>T(n)=O(n^lg3) size_t m=a.size(); vector<Polynomial>a0,a1,b0,b1; vector<vector<Polynomial> >c; c.resize(3);//由于递归式只含3项(f(x)=c[0]+c[1]x^(n/2)+c[2]x^n),所以c只增加3个元素。 for (size_t s=0;s<c.size();s++)//为双重vector向量(相当于二维数组)开辟内存 { c[s].resize(2*m+1);//而resize改变了vector的capacity同时也增加了它的size! }//而这3个元素中的每个元素也是一个向量,这个向量是两个m次多项式乘积,所以结果是一个2*m+1次多项式。 if (m==2)//多项式为2项时,其原理为:(a+bx)(c+dx)=ac+((a+b)(c+d)-ac-bd)x+bdx^2 { c[0][0]=a[0]*b[0]; c[0][2]=a[1]*b[1]; c[0][1]=(a[0]+a[1])*(b[0]+b[1])-c[0][2]-c[0][0]; c[0][0].index=0;//多项式为2项时,指数固定只有0,1,2 c[0][1].index=1;//同上 c[0][2].index=2;//同上 return c[0]; } a0.reserve(m / 2);//vector 的reserve增加了vector的capacity,但是它的size没有改变! a1.reserve(m / 2);//同上 b0.reserve(m / 2);//同上 b1.reserve(m / 2);//同上 for (int i = 0,j=m/2; i<m/2,j<m; i++,j++) {//将多项式的高次项和低次项各分一半。 a0.push_back(a[i]); a1.push_back(a[j]); b0.push_back(b[i]); b1.push_back(b[j]); }//以下是递归式f(x)=c[0]+c[1]x^(n/2)+c[2]x^n c[0]=Polynomial_multiplication(a0,b0);//T(n/2) c[2]=Polynomial_multiplication(a1,b1);//T(n/2) c[1]=Polynomial_multiplication(a0+a1,b0+b1)-c[2]-c[0];//T(n/2) vector<Polynomial>y;//向量y表示了递归式f(x)的各项系数与指数。 y.resize(c[0].size()+c[1].size()+c[2].size()); size_t k=0,h=0; for (;k<c[0].size();k++,h++) { y[h].coef=c[0][k].coef; y[h].index=c[0][k].index; } for ( k=0;k<c[1].size();k++,h++) { y[h].coef=c[1][k].coef; y[h].index=c[1][k].index+m/2; } for ( k=0;k<c[2].size();k++,h++) { y[h].coef=c[2][k].coef; y[h].index=c[2][k].index+m; } return y; } void main() { struct Polynomial y; vector<Polynomial>a(n,y),b(n,y); int x,i=0,j=0,flag1=0; cout<<"请输入项数不超过"<<n<<"的多项式a"<<endl; while (i!=n&&cin>>x) { a[i].coef=x; i++; } cout<<"请输入项数不超过"<<n<<"的多项式b"<<endl; while (j!=n&&cin>>x) { b[j].coef=x; j++; } vector<Polynomial> yy=Polynomial_multiplication(a,b); vector<Polynomial>flag; flag.resize(yy.size()); int i1=0; while(i1!=yy.size()) flag[i1++]=y; for (int k=0;k<yy.size();k++)//合并同类项 { flag[yy[k].index].coef+=yy[k].coef; flag[yy[k].index].index=yy[k].index; } for (int k1=0;k1<2*n;k1++)//显示多项式乘积结果 { if(flag[k1].coef==0)continue; if (flag[k1].coef<0) { cout<<flag[k1].coef<<"x^"<<flag[k1].index; } else { if (!flag1) { cout<<flag[k1].coef<<"x^"<<flag[k1].index; flag1=1; } else cout<<"+"<<flag[k1].coef<<"x^"<<flag[k1].index; } } cout<<endl; }
//O(n^lg3)的多项式乘法(奇偶次数划分),这个多项式乘法递归函数总体来讲和书上的FFT结构类似。 #include <iostream> #include <vector> #include <math.h> using namespace std; #define n 8 //n始终是2的幂,不满2的幂的多项式用0为系数的项自动补满使项数达到2的幂 //int t=-1; int Log(int nn) { int i=0; while (nn>>=1)i++; return i; } struct Polynomial { int coef;//系数 int index;//指数 Polynomial(int c=0,int i=0){coef=c,index=i;}; }; vector<Polynomial> operator+(vector<Polynomial>const &a,vector<Polynomial>const &b)//运算符重载函数,下面几个函数类似。 { vector<Polynomial>temp; temp.resize(a.size()); for ( int i=0;i<a.size();i++) { temp[i].coef=a[i].coef+b[i].coef; temp[i].index=a[i].index; } return temp; } vector<Polynomial> operator-(vector<Polynomial>const &a,vector<Polynomial>const &b) { vector<Polynomial>temp; temp.resize(a.size()); for (size_t i=0;i<a.size();i++) { temp[i].coef=a[i].coef-b[i].coef; temp[i].index=a[i].index; } return temp; } Polynomial operator+(const Polynomial&a,const Polynomial&b) { Polynomial temp; temp.coef=a.coef+b.coef; return temp; } Polynomial operator-(const Polynomial&a,const Polynomial&b) { Polynomial temp; temp.coef=a.coef-b.coef; return temp; } Polynomial operator*(const Polynomial&a,const Polynomial&b) { Polynomial temp; temp.coef=a.coef*b.coef; temp.index=a.index+b.index; return temp; } vector<Polynomial> Polynomial_multiplication(vector<Polynomial>&a,vector<Polynomial>&b)//多项式乘法 {//T(n)=3T(n/2)+O(n) =>T(n)=O(n^lg3) size_t m=a.size(); vector<Polynomial>a0,a1,b0,b1; vector<vector<Polynomial> >c; c.resize(3);//由于递归式只含3项(f(x)=c[0]+c[1]x^(n/2)+c[2]x^n),所以c只增加3个元素。 for (size_t s=0;s<c.size();s++)//为双重vector向量(相当于二维数组)开辟内存 { c[s].resize(2*m-1);//而resize改变了vector的capacity同时也增加了它的size! }//而这3个元素中的每个元素也是一个向量,这个向量是两个m次多项式乘积,所以结果是一个2*m+1次多项式。 if (m==2)//多项式为2项时,其原理为:(a+bx)(c+dx)=ac+((a+b)(c+d)-ac-bd)x+bdx^2 { c[0][0]=a[0]*b[0]; c[0][2]=a[1]*b[1]; c[0][1]=(a[0]+a[1])*(b[0]+b[1])-c[0][2]-c[0][0]; c[0][1].index=a[0].index+b[1].index;//注意c[0][1]的指数处理问题 return c[0]; } a0.reserve(m / 2);//vector 的reserve增加了vector的capacity,但是它的size没有改变! a1.reserve(m / 2);//同上 b0.reserve(m / 2);//同上 b1.reserve(m / 2);//同上 for (int i = 0; i<m/2; i++) {//将多项式的高次项和低次项各分一半。 a0.push_back(a[2*i]); a1.push_back(a[2*i+1]); b0.push_back(b[2*i]); b1.push_back(b[2*i+1]); }//以下是递归式f(x)=c[0]+c[1]x^(n/2)+c[2]x^n c[0]=Polynomial_multiplication(a0,b0);//T(n/2) c[2]=Polynomial_multiplication(a1,b1);//T(n/2) c[1]=Polynomial_multiplication(a0+a1,b0+b1)-c[2]-c[0];//T(n/2) vector<Polynomial>y;//向量y表示了递归式f(x)的各项系数与指数。 y.resize(c[0].size()+c[1].size()+c[2].size()); size_t k=0,h=0; for (;k<c[0].size();k++,h++) { y[h].coef=c[0][k].coef; y[h].index=c[0][k].index; } for ( k=0;k<c[1].size();k++,h++) { y[h].coef=c[1][k].coef; y[h].index=c[1][k].index+pow(2,(Log(n)-Log(m)));//注意c[1]的指数处理问题 } for ( k=0;k<c[2].size();k++,h++) { y[h].coef=c[2][k].coef; y[h].index=c[2][k].index; } return y; } void main() { struct Polynomial y; vector<Polynomial>a(n,y),b(n,y); int x,i=0,j=0,flag1=0; cout<<"请输入项数不超过"<<n<<"的多项式a"<<endl; while (i!=n&&cin>>x) { a[i].coef=x; a[i].index=i; i++; } cout<<"请输入项数不超过"<<n<<"的多项式b"<<endl; while (j!=n&&cin>>x) { b[j].coef=x; b[j].index=j; j++; } vector<Polynomial> yy=Polynomial_multiplication(a,b); cout<<endl; vector<Polynomial>flag; flag.resize(yy.size()); int i1=0; while(i1!=yy.size()) flag[i1++]=y; for (int k=0;k<yy.size();k++)//合并同类项 { flag[yy[k].index].coef+=yy[k].coef; flag[yy[k].index].index=yy[k].index; } for (int k1=0;k1<2*n;k1++)//显示多项式乘积结果 { if(flag[k1].coef==0)continue; if (flag[k1].coef<0) { cout<<flag[k1].coef<<"x^"<<flag[k1].index; } else { if (!flag1) { cout<<flag[k1].coef<<"x^"<<flag[k1].index; flag1=1; } else cout<<"+"<<flag[k1].coef<<"x^"<<flag[k1].index; } } cout<<endl; }c.证明:请说明如何用O(n^lg3)步计算出两个n位整数的乘积,其中每一步至多常数个1位的值进行操作。
//O(n^lg3)的多项式乘法转化为两个n位整数乘法,这个多项式乘法递归函数总体来讲和书上的FFT结构类似 #include <iostream>//更精确的说是(1/2)n^lg3次递归 #include <vector> using namespace std; #define n 8 //n始终是2的幂,不满2的幂的多项式用0为系数的项自动补满使项数达到2的幂 struct Polynomial { int coef;//系数 int index;//指数 Polynomial(int c=0,int i=0){coef=c,index=i;}; }; Polynomial operator-(Polynomial&a,Polynomial&b)//运算符重载函数,下面几个函数类似。 { Polynomial temp; temp.coef=a.coef-b.coef; return temp; } vector<Polynomial> operator+(vector<Polynomial>&a,vector<Polynomial>&b) { vector<Polynomial>temp; temp.resize(a.size()); for (size_t i=0;i<a.size();i++) { temp[i].coef=a[i].coef+b[i].coef; temp[i].index=a[i].index; } return temp; } vector<Polynomial> operator-(vector<Polynomial>&a,vector<Polynomial>&b) { vector<Polynomial>temp; temp.resize(a.size()); for (size_t i=0;i<a.size();i++) { temp[i].coef=a[i].coef-b[i].coef; temp[i].index=a[i].index; } return temp; } Polynomial operator+(Polynomial&a,Polynomial&b) { Polynomial temp; temp.coef=a.coef+b.coef; return temp; } Polynomial operator*(Polynomial&a,Polynomial&b) { Polynomial temp; temp.coef=a.coef*b.coef; return temp; } vector<Polynomial> Polynomial_multiplication(vector<Polynomial>&a,vector<Polynomial>&b)//多项式乘法 {//T(n)=3T(n/2)+O(n) =>T(n)=O(n^lg3) size_t m=a.size(); vector<Polynomial>a0,a1,b0,b1; vector<vector<Polynomial> >c; c.resize(3);//由于递归式只含3项(f(x)=c[0]+c[1]x^(n/2)+c[2]x^n),所以c只增加3个元素。 for (size_t s=0;s<c.size();s++)//为双重vector向量(相当于二维数组)开辟内存 { c[s].resize(2*m+1);//而resize改变了vector的capacity同时也增加了它的size! }//而这3个元素中的每个元素也是一个向量,这个向量是两个m次多项式乘积,所以结果是一个2*m+1次多项式。 if (m==2)//多项式为2项时,其原理为:(a+bx)(c+dx)=ac+((a+b)(c+d)-ac-bd)x+bdx^2 { c[0][0]=a[0]*b[0]; c[0][2]=a[1]*b[1]; c[0][1]=(a[0]+a[1])*(b[0]+b[1])-c[0][2]-c[0][0]; c[0][0].index=0;//多项式为2项时,指数固定只有0,1,2 c[0][1].index=1;//同上 c[0][2].index=2;//同上 return c[0]; } a0.reserve(m / 2);//vector 的reserve增加了vector的capacity,但是它的size没有改变! a1.reserve(m / 2);//同上 b0.reserve(m / 2);//同上 b1.reserve(m / 2);//同上 for (int i = 0,j=m/2; i<m/2,j<m; i++,j++) {//将多项式的高次项和低次项各分一半。 a0.push_back(a[i]); a1.push_back(a[j]); b0.push_back(b[i]); b1.push_back(b[j]); }//以下是递归式f(x)=c[0]+c[1]x^(n/2)+c[2]x^n c[0]=Polynomial_multiplication(a0,b0);//T(n/2) c[2]=Polynomial_multiplication(a1,b1);//T(n/2) c[1]=Polynomial_multiplication(a0+a1,b0+b1)-c[2]-c[0];//T(n/2) vector<Polynomial>y;//向量y表示了递归式f(x)的各项系数与指数。 y.resize(c[0].size()+c[1].size()+c[2].size()); size_t k=0,h=0; for (;k<c[0].size();k++,h++) { y[h].coef=c[0][k].coef; y[h].index=c[0][k].index; } for ( k=0;k<c[1].size();k++,h++) { y[h].coef=c[1][k].coef; y[h].index=c[1][k].index+m/2; } for ( k=0;k<c[2].size();k++,h++) { y[h].coef=c[2][k].coef; y[h].index=c[2][k].index+m; } return y; } void main() { struct Polynomial y; vector<Polynomial>a(n,y),b(n,y); int x,i=0,j=0,flag1=0,i1=0; cout<<"请输入不超过"<<n<<"位数a"<<endl; while (i!=n&&cin>>x) { a[i++].coef=x; } cout<<"请输入不超过"<<n<<"位数b"<<endl; while (j!=n&&cin>>x) { b[j++].coef=x; } vector<Polynomial> yy=Polynomial_multiplication(a,b); vector<Polynomial>flag; flag.resize(yy.size()); while(i1!=yy.size()) flag[i1++]=y; for (int k=0;k<yy.size();k++)//合并同类项 { flag[yy[k].index].coef+=yy[k].coef; flag[yy[k].index].index=yy[k].index; } while (i>0)//显示整数 { if(!a[--i].coef&&flag1==0)continue; else {flag1=1;cout<<a[i].coef;} } cout<<"X"; flag1=0; while (j>0)//显示整数 { if(!b[--j].coef&&flag1==0)continue; else {flag1=1;cout<<b[j].coef;} } cout<<"="; for ( k=0;k<2*n;k++)//进位循环 { if (flag[k].coef>=10) { flag[k+1].coef+=flag[k].coef/10; flag[k].coef%=10; } } flag1=0; for (int k1=2*n-1;k1>=0;--k1)//n位整数相乘结果 { if(!flag[k1].coef&&flag1==0)continue; else {flag1=1;cout<<flag[k1].coef;} } }
//n维特普利茨矩阵Xn维向量,2个n维特普利茨矩阵相乘的算法和这个类似,所以不再给出相应程序。 #include <iostream> #include <math.h> #include <vector> using namespace std; #define pi 3.1415926535 struct Complex { double real; double imag; int num; Complex(int i=0,int j=0){real=i,imag=j;} }; Complex q(1,0); Complex operator+ (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real =lhs.real+rhs.real; temp.imag = lhs.imag+ rhs.imag; return temp; } Complex operator- (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real - rhs.real; temp.imag = lhs.imag - rhs.imag; return temp; } Complex operator* (Complex const & lhs, Complex const & rhs) { Complex temp; temp.real = lhs.real * rhs.real - lhs.imag * rhs.imag; temp.imag= lhs.real * rhs.imag + lhs.imag * rhs.real; return temp; } Complex operator* ( const int &lhs, Complex const & rhs) { Complex temp; temp.real=lhs*rhs.real; temp.imag=lhs*rhs.imag; return temp; } Complex operator / ( const double &lhs, Complex const & rhs) { Complex temp; temp.real=(rhs.real)/lhs; temp.imag=(rhs.imag)/lhs; return temp; } vector<Complex> operator* (vector<Complex>const&a,vector<Complex>const&b) { vector<Complex> temp; for (size_t i=0;i<a.size();i++) { temp.push_back(a[i]*b[i]); } return temp; } vector<double> operator* (const int j,vector<double>const&a) { vector<double> temp; for (size_t i=0;i<a.size();i++) { temp.push_back(j*a[i]); } return temp; } vector<Complex> operator+ (vector<Complex>const&a,vector<Complex>const&b) { vector<Complex> temp; for (size_t i=0;i<a.size();i++) { temp.push_back(a[i]+b[i]); } return temp; } vector<double> operator+ (vector<double>const&a,vector<double>const&b) { vector<double> temp; for (size_t i=0;i<a.size();i++) { temp.push_back(a[i]+b[i]); } return temp; } vector<double> operator- (vector<double>const&a,vector<double>const&b) { vector<double> temp; for (size_t i=0;i<a.size();i++) { temp.push_back(a[i]-b[i]); } return temp; } istream &operator>>(istream&is, Complex &item) { is >> item.real>>item.imag; return is; } vector<Complex> recursive_FFT(vector<Complex> const&a) { size_t n = a.size();//有改动 if (n == 1) return a; struct Complex wn, w; wn.real = cos(2 * pi / n), wn.imag = sin(2 * pi / n); w.real = 1, w.imag = 0; vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++) { a0.push_back(a[i * 2]); a1.push_back(a[i * 2 + 1]); } vector<Complex>y0 = recursive_FFT(a0); vector<Complex>y1 = recursive_FFT(a1); vector<Complex>y; y.resize(n); for (int k = 0; k<n / 2; k++) { y[k] = y0[k] + w*y1[k]; y[k + n / 2] = y0[k] - w*y1[k]; w = w*wn; } return y; } vector<Complex> recursive_FFT_opposite(vector<Complex> const&a) { size_t n = a.size(); if (n == 1) return a; struct Complex wn, w; wn.real = cos(-2 * pi / n), wn.imag = sin(-2 * pi / n);// 注意求DFT的逆是负数的 w.real = 1, w.imag = 0; vector<Complex>a0, a1; a0.reserve(n / 2); a1.reserve(n / 2); for (int i = 0; i<n / 2; i++) { a0.push_back(a[i * 2]); a1.push_back(a[i * 2 + 1]); } vector<Complex>y0 = recursive_FFT_opposite(a0); vector<Complex>y1 = recursive_FFT_opposite(a1); vector<Complex>y; y.resize(n); for (int k = 0; k<n / 2; k++) { y[k] = y0[k] + w*y1[k]; y[k + n / 2] = y0[k] - w*y1[k]; w = w*wn; } return y; } vector<Complex> Polynomial_multiplication(vector<Complex> const&a,vector<Complex> const&b)//O(nlgn) { vector<Complex>ya=recursive_FFT(a); vector<Complex>yb=recursive_FFT(b); vector<Complex>yc=ya*yb; vector<Complex>temp=recursive_FFT_opposite(yc);//应用卷积定理 return temp; } vector<double> Circ_Circ(vector<Complex>y,int k1,int n)//两个循环矩阵相乘 {//O(n) vector<double>yy(k1,0); for (int t = 0; t<=k1-1; t++) { if (t==k1-1) { yy[t]=y[t].real/n; break; } if (fabs(y[t].real) < 0.001) y[t].real=0;//将小于0.001的数据置为0 if (fabs(y[k1+t].real) < 0.001) y[k1+t].real=0; //同上 yy[t]=y[t].real/n+y[k1+t].real/n; } return yy; } vector<double> Triangular_Toeplitz_Circ(vector<Complex>&y,int k1,int n)//循环矩阵与上三角特普利茨矩阵乘积结果 {//O(n) vector<double>yy(k1,0); for (int t = 0; t<=k1-1; t++) { if (fabs(y[t].real) < 0.001) y[t].real=0;//将小于0.001的数据置为0 yy[t]=y[t].real/n; } return yy; } void Toeplitz(vector<vector<double> >&T,vector<Complex>&c,vector<Complex>&s,int m)//O(n) {//特普利茨矩阵可以分解成一个循环矩阵和一个斜循环矩阵的和 Complex y; size_t n=T[0].size(); s.resize(m,y),c.resize(m,y); c[0].real=T[0][0];c[0].imag=0; for (size_t i=1;i<n;i++) c[i].real=(T[0][i]+T[n-i][0])/2.0; s[0]=y; for ( i=1;i<n;i++) s[i].real=(T[0][i]-T[n-i][0])/2.0; } vector<double> Toeplitz_vector(vector<vector<double> >&T,vector<Complex>&c,vector<Complex>&s,vector<Complex>b,int n1,int n) { Toeplitz(T,c,s,n);//O(n) vector<Complex>y = Polynomial_multiplication(c,b);//循环矩阵X向量O(nlgn) vector<Complex>y1=Polynomial_multiplication(b,s);//斜矩阵X向量O(nlgn) vector<double>y2=Circ_Circ(y, n1,n);//循环矩阵C1X向量b的结果O(n) vector<double>y3=Circ_Circ(y1, n1,n);//循环矩阵S1X向量b的结果O(n) vector<double>y4=Triangular_Toeplitz_Circ(y1,n1,n);//上三角特普利茨矩阵X向量b的结果O(n) vector<double>y6=y2+2*y4-y3;//一般的特普利茨矩阵X向量b的结果O(n) return y6;//O(n)+O(nlgn)+O(nlgn)+O(n)+O(n)+O(n)+O(n)=O(nlgn) } void main() { cout << "请输入需要计算的矩阵与向量的维数n的接近2n的2的幂得值:" << endl; int j = 0;//对于n维矩阵与向量,我们需要输入刚好大于等于2n的2的幂,比如对于5X5矩阵和5维向量,那么大于等于10的2的幂的值是16. cin >> j; const int n = j; cout<<"打算输入几个有效数据?且不能超过"<<n/2<<"个数"<<endl; int j1=0; cin>>j1; const int n1=j1; int k=0; Complex i2; vector<Complex>b,c,s; cout << "请输入循环矩阵B(代替向量B)的第一行各项(有效数据"<<n1<<"个,其余项数补0):"; while (k != n&&cin>>i2) { b.push_back(i2); k++; } vector<vector<double> >T; T.resize(n1); for (size_t i=0;i<T.size();i++) T[i].resize(n1); cout<<"请输入特普利茨矩阵的第一行数据,且数据不能超过"<<n1<<"个"<<endl; for ( i=0;i<T[0].size();i++) cin>>T[0][i]; cout<<"请输入特普利茨矩阵的第一列数据,且数据不能超过"<<n1-1<<"个"<<endl; for ( i=1;i<T.size();i++) cin>>T[i][0]; vector<double>y=Toeplitz_vector(T,c,s,b,n1,n); cout<<n1<<"维"<<"特普利茨矩阵和"<<n1<<"维向量相乘结果="; for (size_t g=0;g<y.size();g++) { cout<<y[g]<<" "; } cout<<endl; }