在網絡上找的我好辛苦啊!!!因為本人太蒟了,看了好多博客都沒看懂,然后莫名秒懂。
原理:一個數能夠被拆分為任意二進制的和。 (這個原理造出來好多算法啊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];