完全背包
浅解:就是必须将背包装满
原题摘录
简要解析
显然,这是一个完全背包问题.问题就是挑选物品,把总体积凑成40有多少种凑法?枚举显然不行.因为枚举每个物品选还是不选,有2^20种.
先可以尝试使用递归的思想.递归是很多思想的一个起点.也最容易想到.以及从他出发优化出更好的办法.
把ways(int w,int k)表示为从前k种物品凑成体积为w的凑法总数,那我们要求的不就是ways(40,n),n为输入的物品种数.
int ways(int w,int k){
if(w==0) return 1;
if(k<=0) return 0;//还差一定的体积但是已经没有物品可选了
int a=ways(w,k-1);//没有第k种
int b=ways(w-a[k],k-1);//有第k种
return a+b;
}
进一步转化为记忆型动归,显然这里有两个变量,故用二维数组ways[w][k];
int main(){
cin>>N;
memset(ways,0,sizeof(ways));
for(i=1;i<=n;i++){
cin>>a[i];
ways[0][i]=1;//边界条件
}
ways[0][0]=1;
for(int w=1;w<=40;w++){
for(int k=1;k<=N;k++){
ways[w][k]=ways[w][k-1];
if(w-a[k]>=0)
ways[w][k]+=ways[w-a[k]][k-1];
}
}
cout<<ways[40][N];
return 0;
}
0-1背包
浅解:背包容量可以有剩余,东西要么拿,要么不拿.
原题摘录
N 个物品每个物品有价值d[i],重量w[i], 给定背包最大承重M,求背包能够装载的最大价值。每个物品只有放入背包和不放入背包两种选择。
简要解析
同上题:
我们用F[i][j]表示取前i种物品,总体积不超过j的最优取法的价值总和.
同样可以转化为记忆型动归:(取还是不取第i种)
F[i][j]=max{F[i-1][j],F[i-1][j-w[i]]+d[i]}
但是,可以发现,若总体积很大时,二维数组就要开的很大,最终导致内存不够.
注意到了这个二维数组的下一行的值,只用到了上一行的正上方及左边的值,因此可以采用滚动数组的思想,只要一行即可.所以,可以使用一维数组,递推型动归实现.
int n, m;//物品数,背包容量
while (cin >> n >> m)
{
int i, j;
for (i = 1; i <= n; i++)
cin >> c[i] >> v[i];
memset(f, 0, sizeof f);
for (i = 1; i <= n; i++)
for(j = m; j >= c[i]; j--)
if (f[j] < f[j - c[i]] + v[i])
f[j] = f[j - c[i]] + v[i];
cout << f[m] << "\n";
}