【算法系列】分治法

1. 分治法

1.1      算法描述:

分治法(divide and conquer algorithms, D&C )是使用一种“分而治之”的思想。好比古代一个国家的土地,分给了多个诸侯共同治理的过程。

分治法的精髓在于三个步骤:

分 – 将问题分解成规模更小的子问题;

治 – 对每个子问题分别采用相同的方法逐一击破;

合 – 将已解决的子问题的解合并起来得到母问题的解。

一般的,在程序上,分治法通常通过递归来实现。类似的,像排序算法中的快速排序、归并排序等。但是并不是所有递归,都是一个最好的分治算法,如下面的斐波那契数列的例子。

分治法,最难的一个步骤是如何进行原问题分解成规模更小的子问题。而算法的效率往往取决于分解得到后子问题的规模。每一步分解得到的子问题规模越小,则算法的效率越快。假设一个原问题规模为n,则它的子问题规模一般可能k和(n-k)。此处k<=n。而我们在算法处理工程中,有可能两部分都要处理,也有可能只需要处理某一部分的问题。

 

1.2      算法应用

1.2.1   乘法问题(powing a number)

问题描述:给出一个数字x和正整数n(n>=0), 计算xn.

  • 方法一: xn. = x·x·x·x·x…, 算法复杂度:
  • l  方法二(分治法):


算法复杂度:

1.2.2   斐波那契数列(Fibonacci sequence)

问题描述:给出整数n,计算出F(n), F(n)符合斐波那契数列要求;

斐波那契数列公式:


  • l  方法一:递归处理

        递归算法ALG(n):对输入n,若n等于0,函数返回0;对输入n,若n等于1,函数返回1;否则,返回递归处理结果:ALG(n-2)+ALG(n-1);

算法复杂为: 

这个算法是非常慢的(幂指数级别),因为它虽然递归了,但是递归的子问题规模衰减太慢了。而且很明显看出,每次递归处理,实际上做了一些重复工作,比如F(n-1)的子问题其实进一步划分又需要求F(n-2)的解。

  • l  方法二:

   先算出F(0),F(1), F(2), 然后依次算出F(n-2)和F(n-1),最后再求和算出F(n)。

   这个方法相比第一个方法的好处就是不用做更多的重复工作。

算法复杂度为

  • l  方法三:

利用斐波那契数列的性质: 

    对于分子,可以利用乘法问题的分治思想来解决,算法复杂度为。很遗憾,因为计算机处理浮点数时,往往精度不够,所以并不是最理想的方案。

  • l  方法四

      利用斐波那契数列的性质:

    算法复杂度为

1.2.3   矩阵乘法问题

问题描述:

   对于输入矩阵,求矩阵,其中

  • l  方法一(直接矩阵乘法):

算法:

     C矩阵元素个数为n*n,每个元素要进行n次乘法并累加得到,所以算法复杂度为。  

  •    方法二(分治法)

       思路:将规模为n*n矩阵C分解为2*2子矩阵相乘,每个子矩阵规模为n/2 * n/2,如:

             

那么,有一下公式:

             r = ae + bg

             s = af + bh

             t = ce + dg

             u = cf + dh

输入算法复杂度:

然而算到这里,方法二并没有比第一个方法快。但是,聪明的人从上式子找到了突破口,思路是将乘法次数减少,现在进行了8次的乘法,只要我们乘法次数小于8那么我们的算法就能比原来的快。

  • 改进后的算法:

P= a ·(f-h)

P=  (a+b) ·h

P=  (c+d) ·e

P=  d ·(g-e)

P=  (a+b)·(e+h)

P=  (b-d)·(g+h)

P=  (a-c)·(e+f)

r = P5 + P4 – P2 + P6

s= P1 + P2

t= P3 + P4

u= P5 + P1- P3 – P7

改进后的算法复杂度:











你可能感兴趣的:(算法,算法,分治法,乘法问题,矩阵乘法,斐波那契数列)