【回溯法】--01背包问题

【回溯法】--01背包问题回溯法 01 背包问题 1 问题描述 给定 n 种物品和一背包 物品 i 的重量是 wi gt 0 其价值为 vi gt 0 背包的容量为 c 问应如何选择装入背包中的物品 使得装入背包中物品的总价值最大 要求使用回溯法 例如 算法分析 整体思路 01 背包属于找最优解问题 用回溯法需要构造解的子集树 对于每一个物品 i 对于该物品只有选与不选 2 个决策 总共有 n 个物品 可以顺序依次考虑每个物品 这

【回溯法】--01背包问题

1、问题描述

  给定n种物品和一背包。物品i的重量是wi>0,其价值为vi>0,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? (要求使用回溯法)

 例如:

【回溯法】--01背包问题

2、算法分析

【整体思路】

  01背包属于找最优解问题,用回溯法需要构造解的子集树。对于每一个物品i,对于该物品只有选与不选2个决策,总共有n个物品,可以顺序依次考虑每个物品,这样就形成了一棵解空间树: 基本思想就是遍历这棵树,以枚举所有情况,最后进行判断,如果重量不超过背包容量,且价值最大的话,该方案就是最后的答案。

      在搜索状态空间树时,只要左子节点是可一个可行结点,搜索就进入其左子树。对于右子树时,先计算上界函数,以判断是否将其减去(剪枝)。

  上界函数bound():当前价值cw+剩余容量可容纳的最大价值<=当前最优价值bestp。 

    为了更好地计算和运用上界函数剪枝,选择先将物品按照其单位重量价值从大到小排序,此后就按照顺序考虑各个物品。

【举例说明】

  对于n=4的0/1背包问题,其解空间树如图所示,树中的16个叶子结点分别代表该问题的16个可能解。 

【回溯法】--01背包问题

【算法设计】

    利用回溯法试设计一个算法求出0-1背包问题的解,也就是求出一个解向量xi (即对n个物品放或不放的一种的方案)

 其中, (xi = 0 或1,xi = 0表示物体i不放入背包,xi =1表示把物体i放入背包)。

【时间复杂度&&优化】  

  因为物品只有选与不选2个决策,而总共有n个物品,所以时间复杂度为【回溯法】--01背包问题

  因为递归栈最多达到n层,而且存储所有物品的信息也只需要常数个一维数组,所以最终的空间复杂度为O(n)。

相关链接1

相关链接2

相关链接3

【源代码】        

#include 
  
    #include 
   
     //#include 
    
      using namespace std; int n;//物品数量 double c;//背包容量 double v[100];//各个物品的价值 value double w[100];//各个物品的重量 weight double cw = 0.0;//当前背包重量 current weight double cp = 0.0;//当前背包中物品总价值 current value double bestp = 0.0;//当前最优价值best price double perp[100];//单位物品价值(排序后) per price int order[100];//物品编号 int put[100];//设置是否装入,为1的时候表示选择该组数据装入,为0的表示不选择该组数据 //按单位价值排序 void knapsack() { int i,j; int temporder = 0; double temp = 0.0; for(i=1;i<=n;i++) perp[i]=v[i]/w[i]; //计算单位价值(单位重量的物品价值) for(i=1;i<=n-1;i++) { for(j=i+1;j<=n;j++) if(perp[i] 
     
       n) //递归结束的判定条件 { bestp = cp; return; } //如若左子节点可行,则直接搜索左子树; //对于右子树,先计算上界函数,以判断是否将其减去 if(cw+w[i]<=c)//将物品i放入背包,搜索左子树 { cw+=w[i];//同步更新当前背包的重量 cp+=v[i];//同步更新当前背包的总价值 put[i]=1; backtrack(i+1);//深度搜索进入下一层 cw-=w[i];//回溯复原 cp-=v[i];//回溯复原 } if(bound(i+1)>bestp)//如若符合条件则搜索右子树 backtrack(i+1); } //计算上界函数,功能为剪枝 double bound(int i) { //判断当前背包的总价值cp+剩余容量可容纳的最大价值<=当前最优价值 double leftw= c-cw;//剩余背包容量 double b = cp;//记录当前背包的总价值cp,最后求上界 //以物品单位重量价值递减次序装入物品 while(i<=n && w[i]<=leftw) { leftw-=w[i]; b+=v[i]; i++; } //装满背包 if(i<=n) b+=v[i]/w[i]*leftw; return b;//返回计算出的上界 } int main() { int i; printf("请输入物品的数量和背包的容量:"); scanf("%d %lf",&n,&c); /*printf("请输入物品的重量和价值:\n"); for(i=1;i<=n;i++) { printf("第%d个物品的重量:",i); scanf("%lf",&w[i]); printf("第%d个物品的价值是:",i); scanf("%lf",&v[i]); order[i]=i; }*/ printf("请依次输入%d个物品的重量:\n",n); for(i=1;i<=n;i++){ scanf("%lf",&w[i]); order[i]=i; } printf("请依次输入%d个物品的价值:\n",n); for(i=1;i<=n;i++){ scanf("%lf",&v[i]); } knapsack(); backtrack(1); printf("最优价值为:%lf\n",bestp); printf("需要装入的物品编号是:"); for(i=1;i<=n;i++) { if(put[i]==1) printf("%d ",order[i]); } return 0; } 
      
     
    
  

 



版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/176449.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午9:54
下一篇 2026年3月26日 下午9:54


相关推荐

  • export在linux中用法_from . import

    export在linux中用法_from . import镜像下载、域名解析、时间同步请点击阿里云开源镜像站export命令用于将shell变量输出为环境变量,或者将shell函数输出为环境变量。一个变量创建时,它不会自动地为在它之后创建的shell进程所知。而命令export可以向后面的shell传递变量的值。命令语法export[参数]命令参数-f:指向函数。-n:删除变量的导出属性。-p:显示全部拥有导出属性的变量。-pf:显示全部拥有导出属性的函数。-nf:删除函数的导出属性。列出当前所有的环境变量>expo

    2025年9月27日
    5
  • 移动端开发中遇到的坑点及总结(持续更新)

    移动端开发中遇到的坑点及总结(持续更新)前端在移动端开发中遇到的坑点前言一、newDate()在IOS上出现值为NAN的问题二、移动端中input中的文字使用height和line-height等值,文字居中但光标不居中的问题前言本文主要是记录自己在移动端开发中遇到的一些坑点(持续更新)一、newDate()在IOS上出现值为NAN的问题我们常用newDate()去获取时间戳,例如newDate(“2017-08-11…

    2022年6月24日
    25
  • 最新版Maven3.6.3下载与安装

    最新版Maven3.6.3下载与安装Maven下载与安装一、Maven概念​ Maven是一个基于Java平台自动化构建工具发展历程:Make–>Ant–>Maven–>Gradle功能清理:删除编译的结果,为重新编译做准备编译:java–>class将java文件转变为class文件测试:针对项目中的关键点进行测试,亦可用项目中的测试代码去测试开发代码…………

    2022年8月21日
    25
  • C MDI窗体

    C MDI窗体MDI MultipleDocu 窗体被称为多文档窗体 它是很多 Windows 应用程序中常用的界面设计 在一个窗体中打开另一个窗体的方式可以通过设置 MDI 窗体的方式实现 MDI 窗体的设置并不复杂 只需要将窗体的属性 IsMdiContain 设置为 True 即可 在窗体加载事件 Loa

    2026年3月26日
    2
  • Keepalived原理

    Keepalived原理Keepalived 简介 Keepalived 是 Linux 下一个轻量级别的高可用解决方案 高可用 广义来讲 是指整个系统的高可用行 狭义的来讲就是主机的冗余和接管 它与 HeartBeat 实现类似的功能 都可以实现服务或者网络的高可用 但是又有差别 HeartBeat 是一个专业的 功能完善的高可用软件 它提供 HA 软件所需的基本功能 比如 心跳检测 资源接管 检测集群中的服务 在集群节点转移共享

    2026年3月18日
    3
  • 小米手机开启Root权限

    小米手机开启Root权限小米手机开启 root 权限

    2026年3月19日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号