二进制拆分

在网络上找的我好辛苦啊!!!因为本人太蒟了,看了好多博客都没看懂,然后莫名秒懂。

 

原理:一个数能够被拆分为任意二进制的和。 (这个原理造出来好多算法啊QAQ)

T=2p1+2p2+2p3+...+2pn

而且       小于等于       T的所有整数都能被2p1       2p2      2p3      ....     2pn的和表示出来

 

证明我不会,但是我知道任意一个数都有自己的二进制形式,比如     13=1101

小于等于13的二进制数肯定不会超过4位,对于T如果有K位,那么小于等于T的数都不可能大于K位

(因为21 + 22 + 23 ...  + 2p-1   = 2p  - 1)

网络上有个例子就是什么:

20+21+22能表示出1到7的任意整数,那么20+21+22+ 6就能表示出1~13的整数

这个例子的剖析就是说:

一个数表示拆成小于它的所有二的次方的和(这个二次方的指数要是递增的)后会剩下一个数。

 

然后我们这样拆分之后就能用log(n)个数表示出 你想表示出来的1~n中的任意数了

放个二进制拆分的例子直观的感受一下它的用途:

多重背包;

众所周知多重背包的朴素算法就是如果第i件物品有 ki 个,那么我们不妨将i物品直接复制为ki个然后做01背包

这样的时间复杂度是O(nmΣki)的;

这玩意很容易超时啊!!!

算法的复杂度瓶颈就在与我们把物品分成ki个做01背包了,

但是你可以把ki进行二进制拆分,把物品栏中加入重量为wi * (2p),体积为vi *(2p)的物品了

这样拆分后与拆成ki个物品做零一背包是等效的,因为同样都可以表示出加入当前i物品1~ki个的价值以及重量

然后时间复杂度就优化到了O(nmlog(Σki))

核心代码为:

  for(int i = 1 ; i <= n ; i ++)  
   for (int j = 1 ; j <= k[i] ; j <<=1)
   t++,val[t]=j*v[i],waste[t]=j*w[i];           

 

posted @ 2020-08-22 07:59  MYCui  阅读(2909)  评论(1编辑  收藏  举报