0-1背包问题--动态规划解法

72 篇文章 1 订阅
10 篇文章 0 订阅


 问题描述:
      给定n种物品和一背包,物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品(物品不能分割),使得装入背包中物品的总价值最大?

 抽象描述如下:
     x[n]:表示物品的选择,x[i]=1表示选择放进物品i到背包中。
         
 
 问题分析:
         1.抽象之后背包问题转换为找到一个最优的数组,x1,x2,.....,xn的0-1序列。
        
         2.假设最优解的序列为x1,x2,.....,xn,能使背包容量C的总价值最大.

               如果,x1=1,则x2,...,xn是C-w1容量的背包的总价值依然是 最大的序列;
               如果,x1=0,则x2,....,xn是C容量的背包的总价值依然是 最大的序列。
           这就是我们所说的最优子结构性质。
        
         3.进一步分析:我们用m(i,j)表示为已经判断好了i:n的序列的背包最大价值,并且此时的背包剩余的容量为j,对物品i进行判断

                如果j>wi, 就只要做出选择wi和不选择wi情况下,哪种更能使背包的总价值更大:m(i,j)=max{ m(i+1,j),m(i+1,j-wi)+vi}(注意这是个递归式)
                如果j<wi:       m(i,j)=m(i+1,j)
                初始化:        m(n,j)=vn  (j>= wn);
                                m(n,j)=0   (0<=j< wn)
                                m(0,C)=0   
             最终的结果:m(1,C)

        4.依次我们就得到了一个递归的表达式:
               
      
       5.如果单纯的从利用递归,重复计算了很多的值,耗费的时间是很大的,动态规划还需避免这种重复计算,怎样自顶向下或自底向上的计算呢?

          采用列表的方法就可以很好的分析设计自顶向下或自底向上的计算的算法了

 举例分析:
         n=3,c=6,w={4,3,2} v={5,2,1}
         m[i][j]=max{ m[i+1][j], m[i+1][j-w[i]]+v[i] }
         列表如下:
         

          最左边箭头:我们计算的方向,从第3行开始向上计算法值。
          表中红色箭头是我们通过选择做出的结果:列如 m[2][3]=max{m[3][3],m[3][3-w[2]]+v[2]},我们最终选择了m[3][3-w[2]]+v[2]。
          整个问题的最优解保存在m[1][6]中。

 代码实现:
     

// w[]:保存物品重量
// v[]:保存物品价值
// n:物品数目 c:背包容量
//#define max(a,b) (((a) > (b)) ? (a) : (b))
int  KnapsackDP( int  n, int  c)
{
    
int  i,j;
    
// 初始化
     for  (j = 0 ;j <= c;j ++ )
    {
        
if  (j >= w[n])
       m[n][j]
= v[n];
        
else
       m[n][j]
= 0 ;
    }
   

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

}

//构造选择序列x[],x[i]=1表示选择i号物品放到背包中,则x[i]=0表示不选择
void Creatx(int x[])
{
    for (i=1;i<n;i++)
     {
        if (m[i][c]==m[i+1][c])
        {
            x[i]=0;
        }
        else
        {
            x[i]=1;
            c-=w[i];
        }
    }
    x[n]=m[n][c]?1:0;//m[n][C]==0则表示为没有选择第n号物品
 
}



实战:
  HDOJ 2602  http://acm.hdu.edu.cn/showproblem.php?pid=2602

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于动态规划的0-1背包问题及改进,我可以给您一些解释和建议。 0-1背包问题是一个经典的动态规划问题,它的主要思想是将一个可装载重量为W的背包装满所装载物品价值最大化。具体来说,我们有n个物品每个物品有一个重量w和一个价值v,我们需要选择一些物品放入背包中,使得它们的总重量不超过W,且总价值最大。 经典的0-1背包问题可以使用动态规划算法来解决。我们可以定义一个二维数组dp[i][j]表示前i个物品放入一个容量为j的背包中所能得的最大价值。状态转移方程如下: - 当j<w[i],dp[i][j] = dp[i-1][j],即当前背包容量不足以放下第i个物品,只能选择不装入背包。 - 当j>=w[i],dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]]+v[i]),即可以选择不装入第i个物品,此最大价值为dp[i-1][j];或者选择装入第i个物品,此最大价值为dp[i-1][j-w[i]]+v[i]。 最终的结果为dp[n][W]。 以上是经典的0-1背包问题解法。但是在实际应用中,我们可能会遇到一些特殊情况,比如物品价值重量没有整数限制,此我们可以使用分数背包问题算法;或者物品的数量很多,此我们可以使用优化的动态规划算法来解决。 具体来说,我们可以使用一些优化方法来减少计算量,比如: - 倒序遍历:因为状态转移方程中的dp[i-1][j]只依赖于dp[i][j]和dp[i][j-w[i]],所以可以倒序遍历j的值,使得后面的状态可以利用前面已经计算好的状态,减少计算量。 - 滚动数组:由于dp[i][j]只依赖于dp[i-1][.],所以我们可以使用滚动数组的方式,只存储两行数据,从而减少空间复杂度。 - 贪心算法:对于某些特殊情况,可以使用贪心算法来进行优化,比如物品价值重量比率相同,此可以按照单位重量价值从大到小排序,然后依次装入。 以上是一些常用的优化方法,具体的实现可以根据不同的情况进行选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值