倍增算法
在上一篇求LCA的文章中,我们使用了倍增的算法(可以认为是二分思想的逆用),在这里我们来简单了解一下倍增算法的思想。
有这样一个问题,现在有一个数字n,现在要求将n分解为2的幂之和(n = ∑(20 + 21 + 22 + …… + 2i-1 + 2i)),要怎么做?下面来介绍该怎么办,为了说明方便,我们假设n = 9 ,同时设定一个上限值16,也就是从24(令k = 4)开始分解:
(1)9 < 24, 说明k太大了,将k = k - 1,此时n = 9,k = 3,
(2)9 > 23,令9 - 23 = 1,继续将k = k - 1,此时n = 1,k = 2,
(3)1 < 22, 说明k太大了,继续将k = k - 1,此时n = 1,k = 1,
(4)1 < 21, 说明k太大了,继续将k = k - 1,此时n = 1,k = 0,
(5)1 = 20,令1 - 20 = 0,n分解完毕。
总结上面的步骤,可以知道9 = 8 + 1 = 23 + 20 。将以上步骤一般化:,可以得到分解过程实际上就是一个在:预估一个k的上线,然后不断地判断n是否大于等于2k,如果是则n -= 2k,再对k--。以上步骤中有一点可以进行优化,对一个数进行位移操作,左位移就相当于乘以2,那么我们可以对1左位移k位来表示2k这个数字。以上内容具体的实现代码如下:
void doubly(int n) //待分解的数 { int tmp = n; const int MAX = 20; //幂的上限 for(int i = 20; i >= 0; i--) { if(tmp >= (1 << i)) { tmp -= (1 << i); } } }