专题——背包问题

  在这个专题,我为大家带来了一个动态规划中的经典得不能再经典的问题——背包问题,在这个专题我打算讲三类背包问题:01背包、完全背包、多重背包。废话不多说,那我就开始讲解吧O(∩_∩)O~!

01背包问题:

有n个物品,每个物品的重量为weight[i],每个物品的价值为value[i]。现在有一个背包,它所能容纳的重量为total,问:当你面对这么多有价值的物品时,你的背包所能带走的最大价值是多少?

思路:每个物品无非是装入背包或者不装入背包,那么就一个一个物品陆续放入背包中,可以有:状态转移方程:

tab[i][j] = max(tab[i-1][j-weight[i]]+value[i],tab[i-1][j]) ({i,j|0<i<=n,0<=j<=total})

其中i表示放第i个物品,j表示背包所容纳的重量,那么tab[i-1][j-weight[i]]+value[i]表示放入第i物品,刚开始接触会有疑问,tab[i-1][j-weight[i]]这个值,可以这样理解:tab[i-1][j]为装到上一个物品在背包j容量时的最佳值,那么如果我要求在j容量的时候放入现在的i物品的价值,那么是不是要先得到容量为(j-weight[i])时候的价值,即先得到tab[i-1][j-weight[i]],所以 tab[i-1][j-weight[i]]+value[i] 为放入第i物品的价值; tab[i-1][j] 就是不放入第i个物品

动态规划的思维就在这里体现了,即tab[i-1][j]是tab[i][j]的最优解(我觉得上面的思路讲解较容易理解)。

例子:5个物品,(重量,价值)分别为:(5,12),(4,3),(7,10),(2,3),(6,6)。

故有:

1 for i=[weight[0],total]
2     tab[n-1][i]=weight[0]; //n为物品数量
3 for i=[1,n)
4     for j=[weight[i],total]
5         tab[n-i-1][j]= max(tab[n-i][j-weight[i]]+value[i],tab[n-i][j])
6 /*    print tab[0][total]     */

完全背包问题:

有n种物品,每种物品有无限个,每个物品的重量为weight[i],每个物品的价值为value[i]。现在有一个背包,它所能容纳的重量为total,问:当你面对这么多有价值的物品时,你的背包所能带走的最大价值是多少?

有了上面01背包的式子,这题会变的容易理解很多,只是这个式子要有小小的改动。01背包在二维数组上操作,就是为了防止一个物品被放入多次的情况。因此一维数组可以满足完全背包的问题。如下:

tab[j] = max(tab[j-weight[i]]+value[i],tab[j]);({i,j|0<i<=n,0<=j<=total})

根本就是一样的,只不过物品可以被放多次。

故有:

1 for i=[0,n)
2     for(j=weight[i];j<=total;j++)
3         tab[j]=max(tab[j-weight[i]]+value[i],tab[j])
4 /*    print tab[0][total]    */

多重背包问题:

有n种物品,每种物品有amount[i]个,每个物品的重量为weight[i],每个物品的价值为value[i]。现在有一个背包,它所能容纳的重量为total,问:当你面对这么多有价值的物品时,你的背包所能带走的最大价值是多少?

多重和完全更接近,多了数量的限制,用一个count[n]计数数组来限制物品i的数量。当放入第i个物品是较优值的时候,count[i]=count[j-weight[i]]+1)j 的含义请查看代码);这样做是因为,放入第i个物品的操作是基于count[j-weight[i]]放入的,所以当count[i-weight[i]]>=amount[i]时,就要阻止放入即便放入第i个物品是较优值。

故有:

 1 for i=[0,n)            /*将count数组清零*/
 2     for(j=weight[i];j<=total;j++)
 3         if(count[j-weight[i]]<amout[i])
 4             tab[j]=max(tab[j-weight[i]]+value[i],tab[j]);
 5             if(tab[j]=tab[j-weight[i]]+value[i])    
 6 //决定放入i是较优解
 7                 count[i]=count[j-weight[i]]+1
 8         else if(tab[j]=0)               //防止装第1个物品和装其他物品的情况
 9             tab[j]=tab[j-1],count[j]=count[j-1]
10         else count[j]=count[j-1]
11 /*    print tab[0][total]    */

 

posted @ 2017-07-10 16:19  Memoryヾノ战心  阅读(306)  评论(1编辑  收藏  举报