01背包
for(int i=0;i<n;i++) //遍历每一件物品
for(int j=v;j>=wei[i];j--)//遍历背包容量,表示在上一层的基础上,容量为J时,第i件物品装或不装的最优解;
dp[j]=max(dp[j-wei[i]]+val[i],dp[j]);
初始化细节:装满dp[0]=0;其余赋值-INF;不装满全初始化为0;
完全背包
for(int i=0;i<n;i++) //遍历每一类物品
for(int j=wei[i];j<=v;j++)//遍历容量,此时代表第一类物品选了几件。与0/1区别正序遍历
dp[j]=max(dp[j-wei[i]]+val[i],dp[j]);
多重背包
for(int i=0;i<n;i++) //遍历每一个物品
for(int j=0;j<=num[i];j++) //遍历物品的数量
for(int k=m;k>=weight[i];k--) //当做01背包来处理
{ //取01背包情况的dp[k]和dp[k-weight[i]]+value[i]的最大值
dp[k]=max( dp[k],dp[k-weight[i]]+value[i] );
}
二进制优化
优化原因:
多重背包转换成 01 背包问题就是多了个初始化,把它的件数C 用
分解成若干个件数的集合,这里面数字可以组合成任意小于等于C
的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可
以用数字的二进制形式来解释
比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以
组合成任意小于等于7 的数,而且每种组合都会得到不同的数
15 = 1111 可分解成 0001 0010 0100 1000 四个数字
如果13 = 1101 则分解为 0001 0010 0100 0110 前三个数字可以组合成
7以内任意一个数,加上 0110 = 6 可以组合成任意一个大于6 小于13
的数,虽然有重复但总是能把 13 以内所有的数都考虑到了,基于这种
思想去把多件物品转换为,多种一件物品,就可用01 背包求解了。
for(int i=0;i<n;i++)
{
cin>>w[i]>>v[i]>>c[i];//对每一种类的c[i]件物品进行二进制分解
for(int j=1;j<=c[i];j<<=1){ //右移=*2
value[cnt]=j*v[i];
weight[cnt]=j*w[i];
cnt++;
c[i]-=j;
}
if(c[i]>0){
alue[cnt]=c[i]*v[i];
weight[cnt]=c[i]*w[i];
cnt++;
}
}
01背包求解.....
好像单调队列也能优化,多重背包;
下一期整理