背包问题总结

 

简单总结一下今天学的背包的相关知识,多有不足之处,还望谅解!!!

 

背包问题:

  1. 部分背包问题

  2. 0 1  背包问题

  3. 完全背包问题

  4. 多重背包问题

1.部分背包问题(可以只取物品的一部分放入背包)

        采用直观的贪心策略:优先放入''价量比''(价值除以质量最大的,直到背包不能再放入(或物品已取完)。

2. 0 1 背包问题(每个物品只有两种情况 “放” 或 “不放” )

         如果 j < w[ i ] , 则 dp[ i + 1 ][ j ] = dp[ i ][ j ];否则 dp[ i + 1 ][ j ] =  max ( dp[ i ][ j ], dp [i ][ j - w[ i ]] + v[ i ])

    方法1:(二维数组)

int dp[MAXN][MAXN];
for(int i=0; i<n; i++)
    for(int j=0; j<=W; j++)
        if(j<w[i])
            dp[i+1][j]=dp[i][j];
        else
            dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]);
printf("%d\n",dp[n][W]);

      方法2:(一维数组)

int dp[MAXN];
for(int i=0; i<n; i++)
    for(int j=W; j>=w[i]; j--)
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[W]);

 

3.完全背包问题(同一物品有无穷件)

    状态转移方程
     dp[ 0 ][ j ] = 0 ;

     dp[ i + 1 ][ j ] = max (dp[i][j - k * w[ i ] ] + k * v[ i ] )       (0 <= k * w[ i ] <= j )

    按照上述关系可以写出以下代码:(但是这个代码时间复杂度太高了O(n^3))

for(int i=0; i<n; i++)
    for(int j=0; j<=W; j++)
        for(int k=0; k*w[i]<=j; k++)
            dp[i+1][j]=max(dp[i+1][j],dp[i][j-k*w[i]]+k*v[i]);
printf("%d\n",dp[n][W]);

        化简状态方程:

       化简后代码:(复杂度O(nW))

       方法一:(二维数组)

for(int i=0; i<n; i++)
    for(int j=0; j<=W; j++)
        if(j<w[i])
            dp[i+1][j]=dp[i][j];
        else
            dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i]);
printf("%d\n",dp[n][W]);

      方法二:(一维数组)

int dp[MAXN];
for(int i=0; i<n; i++)
    for(int j=w[i]; j<=W; j++)
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[W]);

4. 多重背包(同一物品有多件)

     状态转移方程
      dp[ i ][ j ] =  到第i 个物品为止总重量不超过j 的所有选法中最有可能的最大值
      dp[ i + 1 ][ j ] = max ( dp[ i ][ j ] - k * w[ i ] ] + k * v[ i ] )         (0 <= k <= m[ i ])

      方法一:(复杂度为O(V Σ Mi ) )

for(int i=0; i<n; i++)
{
    int num=m[i];// 用来找a
    for(int k=1; num >0; k< <=1)
    {
        int mul=min(k,num);
        for(int j=W; j>=w[i]*mul; j--)
        {
            dp[j]=max(dp[j],dp[j-w[i]*mul]+v[i]*mul);
        }
        num -=mul;
    }
}
printf("%d\n",dp[W]);

     方法二:O(n * m * w)

for(int i = 0; i < n; i++)//n是物品的种类
{
    for(int k =1; k < m[i]; k++)//m[i]记录的是第i个物品的数量
    {
        for(int j = W; j >= w[i]; j--)//w[i]记录的是第i个物品的重量 W是背包的总容量
        {
            dp[j] = max(dp[j], dp[j - w[i]] + v[i]);//v[i]记录的是第i个物品的价值
        }
    }

}

 

背包问题:

  1. 部分背包问题    贪心

  2. 0 1  背包问题    ( dp[ j ] = max(dp[ j ], dp[ j - w[ i ]] + v[ i ]) )    (j --)  路径记录

  3. 完全背包问题    ( dp[ j ] = max(dp[ j ], dp[ j - w[ i ]] + v[ i ]) )    (j ++) 

  4. 多重背包问题    ( dp[ j ] = max(dp[  j], dp[ j - w[ i ]] + v[ i ]) )  二进制拆分、可行性

 

 

 

 

 

 

C/C++,用 INF = 0x3f3f3f3f表示无穷大,MINN = 0xc0c0c0c0表示无穷小

 

 

如有错误请及时提醒博主更正,(@^ --- ^ @)!!!!!!

 

 

 

 

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值