分治法:主要算法思想就是
divide the problems into one or more subproblems,( 拆分问题)
conquer each subproblem recursively(递归思想)
combine
将大问题拆分为小问题,解决了小问题,再通过这些小问题的答案解决大问题。其实map-reduce并行计算也是采用了这种思想。算法主要来源为麻省理工公开课-算法导论的总结和延伸(这个问题暂且留在以后)
运行时间为:
T(n) =2T(n/2) (size of subproblems)+☉(n) (divide conquer time) = ☉(nlgn) 比如归并排序(merge sort)
下面举几个例子说明这个算法思想
1. 二分查找(针对有序结构高效)
1)divide: 用一个中间值 (☉(1))将整个需要查询的结构拆分为两部分, 左边和右边的值, 将需要查找的x 和middle 值比较
2)conquer: 如果x小于中间值,计算左边拆分掉的部分的中间值,继续和这个值比较知道这个中间值 =x, (循环拆分,比较)
T(n) =T(n/2)+☉(1) = ☉(lgn)
2.连乘问题 x power n (x的n次方)
x power n = x power n2 * x power n/2 n, if n is even
= x power n-1/2 * x power n-1/2 * x, if n is odd
T(n) = T(n/2) + ☉(1) = ☉(lgn)
3. fibinacci numbers
F(n) = 0, n = 0,
= 1, n=1
= F(n-1)+F(n-2), n>1
采用最朴素的递归思想从0递归到n, 需要
T(n) = Ω﹙φ power n﹚
#include<iostream>#include<string.h>#include<stdio.h>
usingnamespacestd;typedeflonglongLL;constintN=2;
structMatrix{
LLm[N][N];};
MatrixA={
1,1,1,0
};
MatrixI={
1,0,0,1
};
Matrixmulti(Matrixa,Matrixb){
Matrixc;
for(inti=0;i<N;i++){
for(intj=0;j<N;j++){
c.m[i][j]=0;
for(intk=0;k<N;k++)
c.m[i][j]+=a.m[i][k]*b.m[k][j];
}}
returnc;}
Matrixpower(MatrixA,intk){
Matrixans=I,p=A;while(k){
if(k&1){
ans=multi(ans,p);k--;}
k>>=1;
p=multi(p,p);}
returnans;}
intmain(){
intn;
while(scanf("%d",&n)!=EOF){
Matrixans=power(A,n-1);printf("%I64d\n",ans.m[0][0]);}
return0;}
矩阵法演进
4. 矩阵乘法
Strassen矩阵乘法是通过递归实现的,它将一般情况下二阶矩阵乘法(可扩展到n阶,但Strassen矩阵乘法要求n是2的幂)所需的8次乘法降低为7次,将计算时间从O(nE3)降低为O(nE2.81)。
矩阵C = AB,可写为
C11 = A11B11 + A12B21
C12 = A11B12 + A12B22
C21 = A21B11 + A22B21
C22 = A21B12 + A22B22
如果A、B、C都是二阶矩阵,则共需要8次乘法和4次加法。如果阶大于2,可以将矩阵分块进行计算。耗费的时间是O(nE3)。
要改进算法计算时间的复杂度,必须减少乘法运算次数。按分治法的思想,Strassen提出一种新的方法,用7次乘法完成2阶矩阵的乘法,算法如下:
M1 = A11(B12 - B12)
M2 = (A11 + A12)B22
M3 = (A21 + A22)B11
M4 = A22(B21 - B11)
M5 = (A11 + A22)(B11 + B22)
M6 = (A12 - A22)(B21 + B22)
M7 = (A11 - A21)(B11 + B12)
完成了7次乘法,再做如下加法:
C11 = M5 + M4 - M2 + M6
C12 = M1 + M2
C21 = M3 + M4
C22 = M5 + M1 - M3 - M7
全部计算使用了7次乘法和18次加减法,计算时间降低到O(nE2.81)。计算复杂性得到较大改进。
附Strassen矩阵乘法代码:
//STRASSEN矩阵乘法算法
#include <iostream.h>
const int N=4; //常量N用来定义矩阵的大小
void main()
{
}
void input(int n,float p[][N])
{
}
void output(int n,float C[][N]) //据矩阵输出函数
{
}
void MATRIX_MULTIPLY(float A[][N],float B[][N],float C[][N])
{
}
void MATRIX_ADD(int n,float X[][N],float Y[][N],float Z[][N]) //矩阵加法函数X+Y—>Z
{
}
void MATRIX_SUB(int n,float X[][N],float Y[][N],float Z[][N]) //矩阵减法函数X-Y—>Z
{
}
void STRASSEN(int n,float A[][N],float B[][N],float C[][N])
{
}