热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

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

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


 问题描述:
      给定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
                初始化:        m(n,j)=vn  (j>= wn);
                                m(n,j)=0   (0<=j
                                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      {
        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


推荐阅读
  • 本实验主要探讨了二叉排序树(BST)的基本操作,包括创建、查找和删除节点。通过具体实例和代码实现,详细介绍了如何使用递归和非递归方法进行关键字查找,并展示了删除特定节点后的树结构变化。 ... [详细]
  • MATLAB实现n条线段交点计算
    本文介绍了一种通过逐对比较线段来求解交点的简单算法。此外,还提到了一种基于排序的方法,但该方法较为复杂,尚未完全理解。文中详细描述了如何根据线段端点求交点,并判断交点是否在线段上。 ... [详细]
  • 本文详细介绍了 React 中的两个重要 Hook 函数:useState 和 useEffect。通过具体示例,解释了如何使用它们来管理组件状态和处理副作用。 ... [详细]
  • libsodium 1.0.15 发布:引入重大不兼容更新
    最新发布的 libsodium 1.0.15 版本带来了若干不兼容的变更,其中包括默认密码散列算法的更改和其他重要调整。 ... [详细]
  • 本文总结了涡喷发动机动平衡的几种有效方法,探讨了不同传感器和软件工具的应用,旨在帮助爱好者和工程师更好地理解和实现动平衡调整,确保发动机高效稳定运行。 ... [详细]
  • 汇编语言等号伪指令解析:探究其陡峭的学习曲线
    汇编语言以其独特的特性和复杂的语法结构,一直被认为是编程领域中学习难度较高的语言之一。本文将探讨汇编语言中的等号伪指令及其对初学者带来的挑战,并结合社区反馈分析其学习曲线。 ... [详细]
  • 离散型随机变量的典型分布:超几何、几何、二项及泊松分布
    本文探讨了几种常见的离散型随机变量分布,包括超几何分布、几何分布、二项分布及其衍生的负二项分布和泊松分布。通过具体的模型和推导过程,详细介绍了这些分布的概率质量函数、期望和方差等关键特征。 ... [详细]
  • 探索1000以内的完美数:因数和等于自身
    本文探讨了如何在1000以内找到所有完美数,即一个数的因数(不包括自身)之和等于该数本身。例如,6是一个完美数,因为1 + 2 + 3 = 6。通过编程实现这一过程,可以更好地理解完美数的特性。 ... [详细]
  • 深入理解Java中的Collection接口与Collections工具类
    本文详细解析了Java中Collection接口和Collections工具类的区别与联系,帮助开发者更好地理解和使用这两个核心组件。 ... [详细]
  • 本文探讨了MariaDB在当前数据库市场中的地位和挑战,分析其可能面临的困境,并提出了对未来发展的几点看法。 ... [详细]
  • 最近团队在部署DLP,作为一个技术人员对于黑盒看不到的地方还是充满了好奇心。多次咨询乙方人员DLP的算法原理是什么,他们都以商业秘密为由避而不谈,不得已只能自己查资料学习,于是有了下面的浅见。身为甲方,虽然不需要开发DLP产品,但是也有必要弄明白DLP基本的原理。俗话说工欲善其事必先利其器,只有在懂这个工具的原理之后才能更加灵活地使用这个工具,即使出现意外情况也能快速排错,越接近底层,越接近真相。根据DLP的实际用途,本文将DLP检测分为2部分,泄露关键字检测和近似重复文档检测。 ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 本文介绍 MATLAB 中匿名函数的构造方法及其在实际编程中的应用。匿名函数是一种简洁的函数表达方式,可以直接在命令行或脚本中定义。例如,定义一个平方函数 `sqr = @(x) x.^2`。此外,匿名函数作为句柄对象,可以方便地传递计算函数,用于求解方程组等复杂问题,如 `fun = @(x) (x-3).*(x-5)`。 ... [详细]
  • 本文详细介绍了Linux系统中init进程的作用及其启动过程,解释了运行级别的概念,并提供了调整服务启动顺序的具体步骤和实例。通过了解这些内容,用户可以更好地管理系统的启动流程和服务配置。 ... [详细]
author-avatar
阿悅11
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有