您的位置:首页 > 其它

01背包问题,是用来介绍动态规划算法最经典的例子

2014-09-19 20:35 316 查看
转自:http://blog.csdn.net/mu399/article/details/7722810
01背包问题,是用来介绍动态规划算法最经典的例子,网上关于01背包问题的讲解也很多,我写这篇文章力争做到用最简单的方式,最少的公式把01背包问题讲解透彻。


01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }

f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值。

Pi表示第i件物品的价值。

决策:为了背包中物品总价值最大化,第 i件物品应该放入背包中吗 ?

题目描述:
有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

nameweightvalue12345678910
a26066991212151515
b23033669991011
c65000666661011
d54000666661010
e460006666666
只要你能通过找规律手工填写出上面这张表就算理解了01背包的动态规划算法。

首先要明确这张表是至底向上,从左到右生成的。

为了叙述方便,用e2单元格表示e行2列的单元格,这个单元格的意义是用来表示只有物品e时,有个承重为2的背包,那么这个背包的最大价值是0,因为e物品的重量是4,背包装不了。

对于d2单元格,表示只有物品e,d时,承重为2的背包,所能装入的最大价值,仍然是0,因为物品e,d都不是这个背包能装的。

同理,c2=0,b2=3,a2=6。

对于承重为8的背包,a8=15,是怎么得出的呢?

根据01背包的状态转换方程,需要考察两个值,
一个是f[i-1,j],对于这个例子来说就是b8的值9,另一个是f[i-1,j-Wi]+Pi;
在这里,
f[i-1,j]表示我有一个承重为8的背包,当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值

f[i-1,j-Wi]表示我有一个承重为6的背包(等于当前背包承重减去物品a的重量),当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值

f[i-1,j-Wi]就是指单元格b6,值为9,Pi指的是a物品的价值,即6

由于f[i-1,j-Wi]+Pi = 9 + 6 = 15 大于f[i-1,j] = 9,所以物品a应该放入承重为8的背包

好,至此我们解决了背包问题中最基本的0/1背包问题。等等,这时你可能要问,
我现在只知道背包能装入宝石的最大价值,但我还不知道要往背包里装入哪些宝石啊。嗯, 好问题!让我们先定义一个数组x,对于其中的元素为1时表示对应编号的宝石放入背包, 为0则不放入。让我们回到上面的例子,对于体积为5,4,3,价值为20,10,12的3个宝石 ,如何求得其对应的数组x呢?(明显我们目测一下就知道x={1
0 1}, 但程序可目测不出来)OK,让我们还是从状态说起。如果我们把2号宝石放入了背包, 那么是不是也就意味着,前3个宝石放入背包的最大价值要比前2个宝石放入背包的价值大, 即:d(3, 10)>d(2, 10)。再用字母代替具体的数字 (不知不觉中我们就用了不完全归纳法哈),当d(i,
j)>d(i-1, j)时,x(i-1)=1;j=j-w[i];OK,

int j=C-1;
for(int i=N-1;i>0;i--)
{
if(d[i][j]>d[i-1][j])
{
x[i]=1;
j=j-w[i];
}
}
if(d[0][j]>0)
x[0]=1;


完整的程序:

#include<iostream>
using namespace std;
const int N=5;
const int C=10;
int v[]={6,4,5,3,6},w[]={4,5,6,2,2};//下标从0开始
int x
;
int d
[C]={0};
void find()
{
for(int j=0;j<C;j++)
{
for(int i=0;i<N;i++)
{
if(i==0)
{
if(w[0]>j)
d[0][j]=0;
else
d[0][j]=v[0];
}
else if(j-w[i]<0)//剩余空间放不下当前的物品
d[i][j]=d[i-1][j];
else
d[i][j]=max(d[i-1][j],d[i-1][j-w[i]]+v[i]);

}
}
}

void main()
{

find();
int j=C-1; for(int i=N-1;i>0;i--) { if(d[i][j]>d[i-1][j]) { x[i]=1; j=j-w[i]; } } if(d[0][j]>0) x[0]=1;
for(int i=0;i<N;i++)
{
if(x[i]==1)
cout<<i<<' ';

}
cout<<endl;
cout<<d[N-1][C-1]<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: