您的位置:首页 > 其它

01背包,完全背包

2017-09-03 10:58 323 查看
01,完全,多重背包模版:

http://blog.csdn.net/u012860063/article/details/32911251

01背包:

转载自:

http://blog.csdn.net/qq_34374664/article/details/52230368

https://www.cnblogs.com/Kalix/p/7622102.html

https://www.cnblogs.com/Kalix/p/7622102.html

先看问题:

有N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

通过阅读问题,因为背包就是要往里面放东西,所以一件物品就是有放或不放两种情况,那么怎么才能判断当前物品该不该放进去从而使利益最大化呢。

首先,我们用i代表前i件物品,v代表包的最大承重,ci是第i件物品的重量、wi是第i件物品的价值、f[i,j]是最大价值(i个物品放入有j个空间的包)。

第一种情况:第i件不放进去,这时所得价值(f[i][j])为:f[i][j]=f[i-1][v]

因为不放进去,所以说当前价值(f[i][j])为前i-1个物品的价值f[i-1][v]:当前i个物品用j个空间所拥有的价值就等于前i-1个物品用j个空间的价值,因为物品i没有放进去,

所以就相当于继承f[i-1][v]了,所以f[i][j]=f[i-1][v]

另一种情况:第i件放进去,这时所得价值为:f[i][j]=f[i-1][v-c[i]]+w[i]

因为放进去了,所以说当前价值(f[i][j])不是前i-1个物品的价值f[i-1][v]:因为你放进去了,所以这个时候包内的空间就不是v了,而应该是v-c[i],所以说,

你现在需要继承前i-1个物品占用体积为v-c[i]时的价值,因为你将物品放进去了,所以还需要加上当前物品价值wi,所以f[i][j]=f[i-1][v-c[i]]+w[i]

因为对于第i件物品就是这两种操作,而你又想要最大价值,所以

f[i][j]=max(f[i-1][v],f[i-1][v-c[i]]+w[i])

贴一段代码:(n为物品数量)

for (int i=1;i<=n;++i) { 
for (int j=v;j>=0;--j) {
if(c[i]<=j)//如果当前物品可以放入当前空间的背包
f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+w[i]);
else
f[i][j]=f[i-1][j];//如果当前物品放不进去,那么继承前i个物品在当前空间大小时的价值
   }
}


我们再进行优化,改变一下dp思路,让f[i][j]表示出在前i种物品中选取若干件物品放入容量为j的背包所得的最大价值。

所以说,对于第i件物品有放或不放两种情况,而放的情况里又分为放1件、2件、……v/c[i]件

如果不放那么f[i][j]=f[i-1][j];如果确定放,那么当前背包中应该出现至少一件第i种物品,所以f[i][j]中至少应该出现一件第i种物品,即f[i][j]=f[i][j-c[i]]+w[i],为什么会是f[i][j-c[i]]+w[i]?

因为我们要把当前物品i放入包内,因为物品i可以无限使用,所以要用f[i][j-c[i]];如果我们用的是f[i-1][j-c[i]],f[i-1][j-c[i]]的意思是说,我们只有一件当前物品i,所以我们在放入物品i的时候需要考虑到第i-1个物品
4000
的价值(f[i-1][j-c[i]]);但是现在我们有无限件当前物品i,我们不用再考虑第i-1个物品了,我们所要考虑的是在当前容量下是否再装入一个物品i,而[j-c[i]]的意思是指要确保f[i][j]至少有一件第i件物品,所以要预留c[i]的空间来存放一件第i种物品。总而言之,如果放当前物品i的话,它的状态就是它自己”i”,而不是上一个”i-1”。

所以说状态转移方程为:

f[i][j]=max(f[i-1][j],f[i][j-c[i]]+w[i])

贴一段代码:

for (int i=1;i<=n;++i)
{
for (int j=v;j>=0;--j)
{
if(t[i]<=j)
f[j]=max(f[j],f[j-c[i]]+c[i]);
else f[j]=f[j];
}
}


完全背包:

先看问题:在n种物品中选取若干件(同一种物品可多次选取)放在空间为v的背包里,每种物品的体积为c1,c2,…,cn,与之相对应的价值为w1,w2,…,wn.求解怎么装物品可使背包里物品总价值最大

看完这个问题,你也许会觉得这个不就是01背包的升级版吗,其实就是这样,完全背包问题与01背包问题的区别在于完全背包每一件物品的数量都有无限个,而01背包每件物品数量只有1个

所以说与它相关的策略已经不是只有取和不取这两种策略了,而是有取0件、取1件、取2件……等等很多种策略

如果我们用和01背包一样的状态,f[i][v]表示前i种物品恰放入一个容量为v的背包的最大价值,那我们应该用k表示当前容量下可以装第i种物品的件数,那么k的范围应该是0≤k≤v/c[i],

既然要用当前物品i把当前容量装满,那需要0≤k≤v/c[i]件,其中k表示件数。

下面给出状态转移方程:

f[i][j] = max{f[i-1][v],f[i-1][v - k * c[i]] + k * w[i]}(0<=k*c[i]<=v)

for (int i = 1; i < n; i++){
for (int j = 1; j <= v; j++){
for (int k = 0; k*c[i] <= j; k++){
    if(c[i]<=j)/*如果能放下*/
    f[i][j] = max{f[i-1][j],f[i-1][j - k * c[i]] + k * w[i]};/*要么不取,要么取0件、取1件、取2件……取k件*/
    else/*放不下的话*/
    f[i][j]=f[i-1][j]/*继承前i个物品在当前空间大小时的价值*/
}
}
}


我们再进行优化,改变一下dp思路,让f[i][j]表示出在前i种物品中选取若干件物品放入容量为j的背包所得的最大价值。

所以说,对于第i件物品有放或不放两种情况,而放的情况里又分为放1件、2件、……v/c[i]件

如果不放那么f[i][j]=f[i-1][j];如果确定放,那么当前背包中应该出现至少一件第i种物品,所以f[i][j]中至少应该出现一件第i种物品,即f[i][j]=f[i][j-c[i]]+w[i],为什么会是f[i][j-c[i]]+w[i]?

因为我们要把当前物品i放入包内,因为物品i可以无限使用,所以要用f[i][j-c[i]];如果我们用的是f[i-1][j-c[i]],f[i-1][j-c[i]]的意思是说,我们只有一件当前物品i,所以我们在放入物品i的时候需要考虑到第i-1个物品的价值(f[i-1][j-c[i]]);但是现在我们有无限件当前物品i,我们不用再考虑第i-1个物品了,我们所要考虑的是在当前容量下是否再装入一个物品i,而[j-c[i]]的意思是指要确保f[i][j]至少有一件第i件物品,所以要预留c[i]的空间来存放一件第i种物品。总而言之,如果放当前物品i的话,它的状态就是它自己”i”,而不是上一个”i-1”。

所以说状态转移方程为:

f[i][j]=max(f[i-1][j],f[i][j-c[i]]+w[i])

for(int i = 0 ; i < n ; i ++)
{
for(int j = 1 ; j <= v ; j++)
{
if(c[i]<=j)
f[i][j] = max(f[i-1][j],f[i][j-c[i]]+w[i]);
else
f[i][j]=f[i-1][j];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: