01背包(超易懂版)
在竞赛题中看到的一道题,虽然不是背包问题,但是用到的方法是相通的,在百度和CSDN上看了很多文章,但是大多数对新手都不太友好。所以今天用比较简单的讲解来教大家01背包问题。
问题原型
01背包,共有n个物体,每个物体有自己的重量和价值,有一个最大承受重量为X的背包 ,向背包中加入物体,问能达到的最大价值为多少。
首先设定物体编号和它的重量价值。
i(物体编号) | 1 | 2 | 3 | 4 |
---|---|---|---|---|
w(物体重量) | 2 | 3 | 4 | 5 |
v(物体价值) | 3 | 4 | 5 | 6 |
设背包的最大的承受重量为8,即X=8。
将物体的重量和价值设为两个数组,即w[i]和v[i]。
本题解法的巧妙之处是运用了二维数组。
本题讲解会先讲如何填写表格,而后在进行代码实现。
上表格。
i/x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
0 | |||||||||
1 | |||||||||
2 | |||||||||
3 | |||||||||
4 |
不要急马上解释。
首先这个表格的第一行代表的是背包的最大承受重量 (可能大家会比较疑惑不是都给最大的承受重量是8了,为啥还要这样,不要急这是我们先让最大的承受重量从0一直向上加,这样做的目的一会会体现出来。),这个表格的第一列为物体的编号(那个0是为了和数组对应。)。
表格内容
表格的内容我用v(i,x)表示(v(i,x)就是我们要建造的二维数组),v(i,x)是加入这个物体时在对应的背包最大承受重量下可以达到的最大价值。
首先是第二行也就是编号对应为0的哪一行,理所应当价值全部为 0。
i/x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | |||||||||
2 | |||||||||
3 | |||||||||
4 |
然后是编号为1的哪一行,因为物体编号为1,w[1]=2,v[1]=3.
当背包的容量为0,1时明显放不下这个物体所以v(1,0)=v(1,1)=0。当最大承受重量x>=2时才能把物体1放进去,这时候只能放物体1。所以这以后的价值为3(即物体1的价值)。
i/x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
2 | |||||||||
3 | |||||||||
4 |
接下来是编号为2的哪一行。当最大承受重量为0,1时放不下物体所以为0。
当x=2时,w[2]>x只能放下物体1所以v(2,2)=v(1,2)=3。
当x=3时,w[2]=x,此时可以放入物体2,此时的放入物体2后还可以放入的重量的为x-w[2]=0;
这时找当最大重量为0时最大的价值为0,加上去就是v(2,3)=w[2]+v(2-1,3-w[2])=4(不要以为这样很多余,就这样分析下去,因为下面填表都是以这个分析为基础的。)。这时候我们还要考虑一个问题当不放这个物体2时,也就是当x=3时只放物体1,此时的价值也就是v(3-1,2)。在这道题时比较特殊因为v[2]=4>v[1]=3。但是如果v[2]=2时呢这个时候肯定不能放物体2了,要放入物体1,这才能保证最大价值。
根据这一个空的分析我们可以写出v(i,x)的表达式
x<w(i) V(i,x)=V(i-1,x)
x>=w(i) V(i,x)=max{V(i-1,x),V(i-1,x-w(i))+v(i)}
以此类推我们就可以填出所有的表格了。我把下面填表的分析省略了大家自己可以按这个思路思考一下…
填好的表如下
i/x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
2 | 0 | 0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 |
3 | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 | 9 |
4 | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 | 10 |
如果你是经过自己的认真思考填出来这个表的话,那样背包问题你就已经掌握了。你会发现
定义的二维数组v(i,x)是当前背包最大承受重量x,前 i 个物品最佳组合对应的价值。
下面只要找出当背包最大承受重量即x=8是所对应的最大价值即可。
代码实现
首先我们要定义两个一维数组数组即w[i],v[i]表示对应物体的重量和价值。
然后定义一个二维数组v[i,x]表示当前背包最大承受重量x,前 i 个物品最佳组合对应的价值。
表示出来就是我们前面填写的表格。
我们的代码主要内容是填表格。
由上面分析可以写出的v[i,j]的关系式,
x<w(i) V(i,x)=V(i-1,x)
x>=w(i) V(i,x)=max{V(i-1,x),V(i-1,x-w(i))+v(i)}
#include<stdio.h>
int max(int x,int y) //因为c语言中没有max函数所以在千米那定义一下
{
int t;
if(x>=y)
{
t=x;
}
else
{
t=y;
}
return(t);
}
int main()
{
int w[5] = {0,2,3,4,5};
int v[5] = {0,3,4,5,6};
int x=8;
int jiazhi[5][9]={{0}};
for(int i=1;i<5;i++)
{
for(int j=1;j<=x;j++)
{
if (j < w[i])
{
jiazhi[i][j] = jiazhi[i - 1][j]; //填表
}
else
{
jiazhi[i][j] = max(jiazhi[i - 1][j], jiazhi[i - 1][j - w[i]]+v[i]); //填表
}
}
}
int mx=0;
for(int i=0;i<5;i++)
{
if(mx<=jiazhi[i][8])
{
mx=jiazhi[i][8];
}
}
printf("%d",mx);
}