#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include <algorithm> /*********************************/ * π的一个近似值 * 其他一些常量 /*********************************/ const double PI = 3.1415926535898; const int SIZE = 1000; /*********************************/ * 复数结构体 /*********************************/ typedef struct complex { complex():real(0.0),image(0.0) {} double real; double image; }Complex; /*********************************/ * 系数与点值数组 * 位反转数组 /*********************************/ Complex a[SIZE],A[SIZE],b[SIZE],B[SIZE],y[SIZE]; int n; int rev[SIZE]; /*********************************/ * 复数乘法,乘法,减 /*********************************/ Complex mult(Complex &a,Complex &b) { Complex ret; ret.real=a.real*b.real-a.image*b.image; ret.image=a.real*b.image+b.real*a.image; return ret; } Complex plus(Complex &a,Complex &b) { Complex ret; ret.real=a.real+b.real; ret.image=a.image+b.image; return ret; } Complex mius(Complex &a,Complex &b) { Complex ret; ret.real=a.real-b.real; ret.image=a.image-b.image; return ret; } /*********************************/ * 计算主n次单位根Wn /*********************************/ Complex expWn(int n) { Complex ret; ret.real= cos(2*PI/n); ret.image= sin(2*PI/n); return ret; } /*********************************/ * 位反转置换 /*********************************/ void initRev() { int lg=(int)(log(n*1.0)/log(2.0)); int range=(1<<lg); for(int i=0;i<range;++i) { int t=i; int k=0; for(int j=0;j<lg;++j,t=t>>1) { k=(k<<1)|(t&1); } rev[i]=k; } } void _reverse(Complex *from,Complex *to) { for(int k=0;k<=n-1;++k) { to[rev[k]] = from[k]; } } /*********************************/ * 快速傅里叶变换 * FFT,O(nlgn) /*********************************/ Complex* iterativeFFT(Complex *from,Complex *to) { initRev(); _reverse(from,to); int lg=(int)(log(n*1.0)/log(2.0)); for(int s=1;s<=lg;++s) { int m= 1<<s; Complex wm=expWn(m); for(int k=0;k<=n-1;k=k+m) { Complex w; w.real=1.0; for(int j=0;j<=m/2-1;++j) { Complex t=mult(w,to[k+j+m/2]); Complex u=to[k+j]; to[k+j]=plus(u,t); to[k+j+m/2]=mius(u,t); w=mult(w,wm); } } } return to; } /*********************************/ * 逆DFT,0(nlgn) * 对点值做乘积并计算最终系数 /*********************************/ Complex* rDFT(Complex *from,Complex *to) { _reverse(from,to); int lg=(int)(log(n*1.0)/log(2.0)); for(int s=1;s<=lg;++s) { int m= 1<<s; Complex wm=expWn(-m); for(int k=0;k<=n-1;k=k+m) { Complex w; w.real=1.0; for(int j=0;j<=m/2-1;++j) { Complex t=mult(w,to[k+j+m/2]); Complex u=to[k+j]; to[k+j]=plus(u,t); to[k+j+m/2]=mius(u,t); w=mult(w,wm); } } } for(int i=0;i<n;++i) { to[i].real/=n; } return to; } Complex* result() { for(int i=0;i<n;++i) { y[i]=mult(A[i],B[i]); } rDFT(y,a); return a; } int main() { scanf("%d",&n); for(int i=0;i<n;++i) { scanf("%lf",&a[i].real); } for(int i=0;i<n;++i) { scanf("%lf",&b[i].real); } iterativeFFT(a,A); iterativeFFT(b,B); result(); for(int i=0;i<n;++i) { printf("a%d:%lf/n",i,a[i].real); } return 0; } 比如计算:6x3+7x2-10x+9 与 -2x3+4x-5 两个多项式的做乘法以后的系数, 输入: 8 9 -10 7 6 0 0 0 0 -5 4 0 -2 0 0 0 0 正确结果应该是:-45,86,-75,-20,44,-14,-12 输入是这样了: a0:-43.875000 a1:84.750000 a2:-74.125000 a3:-19.250000 a4:44.000000 a5:-14.000000 a6:-12.000000 a7:0.000000
算法通过优化两个过程,即系数表示转化成点值表示,需要用n个复根,分别计算它们对应的函数值,作为点值向量.
然后复根点值的计算可以优化,求n个点值的过程优化到nlgn.
最终O(n)将两组点值相乘.
运用nlgn的时间进行点值向系数表示的转化,最终得到多项式相乘的系数结果.