在B站上看了一个关于0-1背包问题的视频,让我对0-1背包有了自己初步的了解,可能不像一些大佬那样流弊哄哄,但是也是个小可爱了。
首先,我们通过一个例题来看看。
题目的大概意思是,有一个小偷拿着麻袋去商场偷东西,小偷的背包大小为W(即小偷只能偷重量之和为小于等于W的物品),商场里有如下表格种类的物品分别对应物品的重量和对应物品的价格,问小偷能偷到的物品的价格之和最大为多少?
标号 | 重量(wk) | 价格(vk) |
---|---|---|
1 | 2 | 3 |
2 | 3 | 4 |
3 | 4 | 5 |
4 | 5 | 8 |
5 | 9 | 10 |
为了方便起见,我们将物品的标号从1开始。
我们用一个二维数组B[k][c]来记录当前偷到的价格(其中k表示前k个物品,c表示剩下多少空间)。我们很容易发现,当第k件物品太重(wk>c)时无法偷走,这时候B[k][c]=B[k-1][c]。当第k件物品没有那么重可以放进包里的时候,这时候我们要考虑,偷还是不偷的问题,这个时候我们就要比较是偷了的价值大,还是不偷的价值大,那么显然,B[k]=max(B[k-1][c-wk]+vk,B[k-1][c])。
综合以上所述,我们可以得到一个递推表达式:
整个递归过程,我们可以以一个分支为例,简单画一下:
旁边的分支我们可以自己拿笔画,可以发现,B[5][20]=26,也就是这道题的实际答案。
#include<stdio.h>
#include<string.h>
//假设包的重量和商品的种类都不超过100
int B[105][105];
int main()
{
int w[105];//商品的重量
int v[105];//商品价值
int N,W;//商品种类、背包重量
int k,c;
memset(B,0,sizeof(B));
memset(w,0,sizeof(w));
memset(v,0,sizeof(v));
printf("请分别输入商品的种类和背包的重量:");
scanf("%d %d",&N,&W);
printf("请分别输入%d种商品的重量和价值:\n",N);
for(int i=1;i<=N;i++)
scanf("%d %d",&w[i],&v[i]);
for(k=1;k<=N;k++)
for(c=1;c<=W;c++)
if(w[k]>c)//商品比背包容量重
B[k][c]=B[k-1][c];
else if(B[k-1][c-w[k]]+v[k]>B[k-1][c])
B[k][c]=B[k-1][c-w[k]]+v[k];
else B[k][c]=B[k-1][c];
printf("%d\n",B[5][20]);
return 0;
}
运行结果如下:
完毕!
第一次学习背包、第一次写文章,有见者请多包涵,另外有错误希望指正!