01背包 完全背包:
#include<bits/stdc++.h>
using namespace std;
int dp[34005],w[3405],v[3405];
int main()
{
int i,j,n,m;
while(~scanf("%d%d",&n,&m))
{
for(i=1; i<=n; i++)
scanf("%d%d",&w[i],&v[i]);
memset(dp,0,sizeof dp);
/* n为物品总数 m为背包总容量 */
for(i=1; i<=n; i++)
for(j=m; j>=w[i]; j--) ///01背包
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
for(i=1; i<=n; i++)
for(j=w[i]; j<=m; j++) ///完全背包
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[m]);
}
}
多重背包:
多重背包问题要求很简单,就是每件物品给出确定的件数,求
可得到的最大价值
多重背包转换成 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 背包求解了。
#include<bits/stdc++.h>
using namespace std;
const int N=100005,M=105;
int dp[N],w[M],v[M],c[M],sw[N],sv[N];
int main()
{
int i,j,t,n,C;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&C);///物品数量 背包容量
int cut=0;
for(i=1; i<=n; i++)
{
scanf("%d%d%d",&w[i],&v[i],&c[i]);///容量 价值 可用数量 c[i]表示该物品数量
for(j=1; j<=c[i]; j<<=1)///对该种类的c[i]件物品进行二进制分解
{
///<<右移1位,相当于乘2
sw[cut]=w[i]*j;
sv[cut++]=v[i]*j;
c[i]-=j;
}
if(c[i]>0)
{
sw[cut]=w[i]*c[i];
sv[cut++]=c[i]*v[i];
}
}
memset(dp,0,sizeof dp);
///经过上面对每一种物品的分解,
///现在sv[]存的就是分解后的物品价值
///sw[]存的就是分解后的物品尺寸
///cut就相当于原来的n
///下面就直接用01背包算法来解
for(i=0; i<cut; i++)
for(j=C; j>=sw[i]; j--)
dp[j]=max(dp[j-sw[i]]+sv[i],dp[j]);
printf("%d\n",dp[C]);
}
}
混合背包:
背包体积为C,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取Mi件(Mi > 1),要么数量无限,在所装物品总体积不超过C的前提下所装物品的价值的和的最大值是多少?
Input
多测试用例。
第一行两个数N和C(C ≤ 200000,N ≤ 200),下面N行每行三个数Vi,Wi,Mi分别表示每个物品的体积、价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=-1表示数量无限。
思路:把所有多重背包转化为01背包,再直接用01背包求解最大值
///混合背包:
#include<bits/stdc++.h>
using namespace std;
const int N=200005,M=205;
int dp[N],w[M],v[M],c[M],sw[N],sv[N];
int main()
{
int i,j,t,n,C;
while(~scanf("%d%d",&n,&C))
{
///物品数量 背包容量
int cut=0;
for(i=1; i<=n; i++)
{
scanf("%d%d%d",&w[i],&v[i],&c[i]);///容量 价值 可用数量 c[i]=-1表示该物品数量无限
if(c[i]==-1) c[i]=C/w[i];
for(j=1; j<=c[i]; j<<=1)///对该种类的c[i]件物品进行二进制分解
{///<<右移1位,相当于乘2
sw[cut]=w[i]*j;
sv[cut++]=v[i]*j;
c[i]-=j;
}
if(c[i]>0)
{
sw[cut]=w[i]*c[i];
sv[cut++]=c[i]*v[i];
}
}
memset(dp,0,sizeof dp);
///经过上面对每一种物品的分解,
///现在Value[]存的就是分解后的物品价值
///size[]存的就是分解后的物品尺寸
///count就相当于原来的n
///下面就直接用01背包算法来解
for(i=0; i<cut; i++)
for(j=C; j>=sw[i]; j--)
{
dp[j]=max(dp[j-sw[i]]+sv[i],dp[j]);
}
printf("%d\n",dp[C]);
}
}