主要总结下快速幂的二进制思想与DP中多重背包的二进制优化:
*1*.快速幂:
看下模板:
原理:将计算a的b次幂时普通的 b次 循环,改为了按照b对应的二进制数每一位的权值及该位上是0或1,从而判断是否需要乘上该位时二进制对应的权值次方。long longpow2(
int
a,
int
b )//求a的b次幂
{
long long
r = 1, base = a;
while
( b != 0 )
{
if
( b%2==1 )
r *= base;
base *= base;
b /= 2;
}
return
r;
}
举个例子。对于求a的21次方(不要管为什么是21),10进制的21对应的二进制数为10101,这时候程序会一边计算21所对应的某一位二进制数,如果是1便让结果r乘上当前的二进制位的权值(即乘上a的n次方)然后权值base平方得到二进制下一位的权值。
其实我很佩服我是怎么纠结着写到这里的。。。目前就理解到这里了。
*2*DP多重背包:
同样先放模板:
首先描述下多重背包的写法:int DP()
{
for(int i=1;i<=n;i++)
{
if(W[i]*Qo[i]>C)//如果个数乘上单位体积大于背包体积就按完全背包算
{
for(int c=0;c<=C;c++)
if(c>=W[i]) F[c]=max(F[c],F[c-W[i]]+V[i]);
}
else//否则先多重再o1
{
int k=1,amount=Qo[i];
while(k<amount)
{
for(int c=C;c>=k*W[i];c--)//计算加上一个体积为k*W[i]的物品
F[c]=max(F[c],F[c-k*W[i]]+k*V[i]);
amount-=k;
k+=k;//二进制加
}
for(int c=C;c>=amount*W[i];c--)
F[c]=max(F[c],F[c-amount*W[i]]+amount*V[i]);//01背包加上剩下的来算最优值
}
}
return F[C];}
1)对于每一种物件,如果其数量足够多以致于整个背包全放这一种物件都不够,那么对该物件做一遍完全背包即可;
2)而如果当某物件的件数*单件体积小于背包体积的话,那么我们就需要思考,到底放几个该物件才最优?而这也是此时的DP转移思路,即枚举放n个该物件进背包的最优值(n≥1并且n≤该物件的件数),即做n遍01背包。
所以在第二步中就出现可以优化的地方了,既然逐个枚举选物件的个数,那么这就产生了重复枚举的弊端。这很显然,比如选择4件该物件的最优值就已经被选1件和选3件时的方案找到过了。
因此在这里根据二进制的特点我们只需要做
小于该物件总件数的2的次幂
,并且最后再把余下的物件个数当做剩下的一个做一遍01背包即可。这里将本来的O(件数*背包体积)减小到(log2件数*背包体积)。