背包问题(0-1背包、完全背包、多重背包)

背包问题

一个背包总容量为V, 现在有N个物品, 第i个物品容量为weight[i], 价值为value[i], 现在往背包里面装东西, 怎样装才能使背包内物品总价值最大.主要分为3类: 
1. 0-1背包, 每个物品只能取0个,或者1个. 
2. 完全背包, 每个物品可以取无限次. 
3. 多重背包, 每种物品都有个数限制, 第i个物品最多可以为num[i]个.

求解思路

利用动态规划(dynamic programming)求最优值的方法,当前状态的最优值可以转化成上一个状态的最优值,与上一个状态转移到当前状态代价的组合求最值。f[i]表示当前状态的最优值,f[i-1]表示上一个状态的最优值,s(i-1, i)表示从状态i-1转移带状态i的代价。则: f[i] = max{f[j], f[j]+s(i-1, i)}

具体问题分类

背包问题可以根据物品个数的限制,有多种情况0-1背包,完全背包,多重背包。

0-1背包问题

0-1背包表示每个物品只有取和不取的状态,即只能取0个或1个。 
用子问题定义状态:即f[i][j]表示前i间物品恰放入一个容器为j的背包可以获得的最大价值。状态转移方程为: 
f[i][j] = max{f[i-1][j], f[i-1][j-weight[i]]+value[i]} 
C代码实现如下:

1     for(int i=1;i<=n;i++)        // i、n分别表示物品编号、总物品数
2     {
3         for(int j=m;j>=0;j--)    // j、m分别表示剩余容量、总容量
4         {
5             if(j>=v[i])     // v[i]表示物品 i 的体积、money etc.
6                 f[j]=max(f[j],f[j-v[i]]+w[i]);   // w[i] 表示物品 i 的重要度
7         }
8     }

 

完全背包问题

完全背包表示每个物品可以取无限次,只要加起来总容量不超过V就可以。 
同样可以用f[i][j]表示前i间物品恰放入一个容器为j的背包可以获得的最大价值。则其状态转移方程为: 
f[i][j] = max{f[i-1][j-k*weight[i]]+k*value[i]} ,其中(0<=k<=j/weight[i]) 
C代码实现如下:

1     for(int i=1;i<=n;i++)
2     {
3         for(int j=0;j<=m;i++)
4         {
5             if(j>=v[i])
6                 f[j]=max(f[j],f[j-v[i]]+w[i]);
7         }
8     }

多重背包问题

多重背包是每个物品有不同的个数限制,如第i个物品个数为num[i]。 
同样可以用f[i][j]表示前i间物品恰放入一个容器为j的背包可以获得的最大价值,且每个物品数量不超多num[i]。则其状态转移方程为: 
f[i][j] = max{f[i-1][j-k*weight[i]]+k*value[i]} ,其中(0<=k<=min{j/weight[i], num[i]})

C代码实现如下:

 

posted @ 2018-06-02 16:05  unbeatable  阅读(342)  评论(0)    收藏  举报