动态规划4:多重背包

1.这里区别一下三种背包:

(1)01背包:背包有最大容量C,给出n种物品,每种物品仅仅一个,有自己的重量和价值wi和vi,求背包可装下的最大价值

(2)完全背包:背包有最大容量C,给出n种物品,每种物品无限个,有自己的重量和价值wi和vi,求背包可装下的最大价值

(3)多重背包:背包有最大容量C,给出n种物品,每种物品给出数量m,有自己的重量和价值wi和vi,求背包可装下的最大价值

2.多重背包解决方法:

对于多重背包我们完全可以把他转化为01背包,每一种都分成一个个的来当做01背包处理,但是一个个分的话效率太低,这里考虑二进制处理。这里引入两个定理:

(1)任何一个数字n都可以拆为 1 + 2^1 + 2^2 + 2^3 + ...... + 2^k + (n - 2^k) 的形式

(2)1 , 2^1 , 2^2 , 2^3 , ....,2^k 可以组合为1 - n之间的任意一个数字

有了以上两条性质我们就不用把每个物品的数量拆成一个一个的了,我们可以拆成2^k , 不仅加快了效率而且这些数字也可以组合为 1 - n间的任意一个数字表示任意一个数量,两全其美。

    int k = 1;
    while(k

3.板子:

(1)若w * k >= C(该物品总重量>=背包总重):可以看作为完全背包处理

(2)若w * k < C  : 当做01背包处理

#include 
#include
#include
#include
#include
using namespace std;
const int maxn = 10000 + 5;
int best[maxn];
int n,C;
void CompletePack(int w,int v)//完全背包(顺序)
{
    for(int i = w;i<=C;i++){
        best[i] = best[i]>best[i - w]+v?best[i]:best[i-w]+v;
    }
}
void ZeroOnePack(int w,int v)//01背包(逆序)
{
    for(int i = C;i>=w;i--){
        best[i] = max(best[i],best[i-w]+v);
    }
}
void MultiplePack(int w,int v,int m)
{
    if(w*m>=C){//当做完全背包处理
        CompletePack(w,v);
        return;
    }
    int k = 1;//分解为01背包(二进制拆分)
    while(k

 

4.例题 

(1) HDU - 2844 Coins

题意:给你n个钱币的数量和价值, 给你一个m ,让求这些钱币能组合成多少种不同的<=m的价值。注意:这里要求支付价钱时,组合是正好的不用找零!

分析:乍一眼以为要从规划数量入手,那样就用不上条件了。其实留意一下题意里的注意,我们还是dp每种价格下最大的组合价值,如果这个是一种组合方式的话 dp[i] == i 了(因为dp[i]为<=i的最大价值),所以我们dp以后在查找一下有多少dp[i] == i即可!注意这里钱币的重量 = 钱币的价值。

代码:

#include 
#include
#include
#include
#include
using namespace std;
const int maxn = 100 + 10;
int w[maxn],v[maxn];
int dp[maxn*1000];
int n,m;
void CompletePack(int W,int V)
{
    for(int i = W;i<=m;i++){
        dp[i] = max(dp[i],dp[i - W] + V);
    }
}
void ZeroOnePack(int W,int V)
{
    for(int i = m;i>=W;i--){
        dp[i] = max(dp[i],dp[i - W] + V);
    }
}
void MultiplePack(int wi,int vi)
{
    if(wi*vi>=m){
        CompletePack(vi,vi);
        return;
    }
    int k = 1;
    while(k

 

你可能感兴趣的:(====动态规划====)