回溯法求解0-1背包问题时比较随机序列和按 v/w 降序排列的算法

问题描述:

针对0-1背包问题,尝试用回溯法。
物品总数N=10,背包容量 C=26, 物品的重量数组为w={7,3,10,12,1,5,7,3,6, 4}, 相应物品价值数组为:v={20,6,15,20,12,10,17,6,3,10} 。
试比较随机序列和按 v/w 降序排列的算法访问节点的个数的差异。

代码实现:

/*
回溯法背包问题
比较随机序列和按 v/w 降序排列的算法访问节点的个数的差异
N=10, C=26, w={7,3,10,12,1,5,7,3,6,4}, v={20,6,15,20,12,10,17,6,3,10}
*/#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <cstdlib>
#include <ctime>
int  fluet=0;
//#include <conio.h>
using namespace std;
int n=10;//物品数量
double c=26;//背包容量
double w[]={0,7,3,10,12,1,5,7,3,6,4};//各个物品的重量 weight
double v[]={0,20,6,15,20,12,10,17,6,3,10}; //各个物品的价值 value
//double v[100];//各个物品的价值 value
//double w[100];//各个物品的重量 weight
double cw = 0;//当前背包重量 current weight
double cp = 0;//当前背包中物品总价值 current value
double bestp = 0;//当前最优价值best price
double perp[100];//单位物品价值(排序后) per price
int order[100];//物品编号
int best_x[100];//用于记录回溯过程的最优情况
int x[100];//设置是否装入,为1的时候表示选择该组数据装入,为0的表示不选择该组数据//按单位价值排序
void knapsack()
{int i,j;int temporder = 0;double temp = 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]<perp[j])//冒泡排序perp[],order[],sortv[],sortw[]{temp = perp[i];  //冒泡对perp[]排序perp[i]=perp[j];perp[j]=temp;temporder=order[i];//冒泡对order[]排序order[i]=order[j];order[j]=temporder;temp = v[i];//冒泡对v[]排序v[i]=v[j];v[j]=temp;temp=w[i];//冒泡对w[]排序w[i]=w[j];w[j]=temp;}}cout<<"按单位价值排序后顺序:"<<endl;for(i=1;i<=n;i++){cout<<order[i]<<" ";} cout<<endl;
}//随机排序
void knapsack_random()
{int i,j;int temporder = 0;double temp = 0;for(i=1;i<=n;i++) {//   int j = parseInt(Math.random() * (n - 1));srand((unsigned)time(NULL)); /*播种子,这里用到了time需要包含头文件time.h*/int j =rand()%n+1;//rand()%n生成0~(n-1)之间随机整数 temporder=order[i];//对order[]随机改变顺序order[i]=order[j];order[j]=temporder;temp = v[i];//相应对v[]改变顺序 v[i]=v[j];v[j]=temp;temp=w[i];//相应对w[]改变顺序w[i]=w[j];w[j]=temp;}cout<<"随机排序后顺序:"<<endl;for(i=1;i<=n;i++){cout<<order[i]<<" ";} cout<<endl;}//回溯函数
void backtrack(int i)
{   //i用来指示到达的层数(第几步,从0开始),同时也指示当前选择玩了几个物品double bound(int i);if(i>n) //递归结束的判定条件{for(int i = 1; i<= n; i++)best_x[i] = x[i];   //记录回溯的最优情况bestp = cp;return;}//如若左子节点可行,则直接搜索左子树;if(cw+w[i]<=c)//将物品i放入背包,搜索左子树{fluet++;cw+=w[i];//同步更新当前背包的重量cp+=v[i];//同步更新当前背包的总价值x[i]=1;backtrack(i+1);//深度搜索进入下一层cw-=w[i];//回溯复原cp-=v[i];//回溯复原x[i]=0;}//对于右子树,先计算上界函数,以判断是否将其减去if(bound(i+1)>bestp)//如若符合条件则搜索右子树{fluet++;x[i]=0;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;for(i=1;i<=n;i++){order[i]=i;}// 按 v/w 降序排列访问cout<<"按 v/w 降序排列的算法访问: "<<endl; knapsack();backtrack(1);cout<<"最优价值为:"<<bestp<<endl;cout<<"需要装入的物品编号是:";for(i=1;i<=n;i++){if(best_x[i]==1)cout<<order[i]<<" ";}cout<<endl;cout<<"访问节点数:"<< fluet<<endl;//随机访问 fluet=0;cout<<"按随机序列的算法访问: "<<endl;knapsack_random();backtrack(1);cout<<"最优价值为:"<<bestp<<endl;cout<<"需要装入的物品编号是:";for(i=1;i<=n;i++){if(best_x[i]==1)cout<<order[i]<<" ";}cout<<endl;cout<<"访问节点数:"<< fluet<<endl; return 0;
}

数据输出:

结果分析:

从这个数据结果输出来看,按 v/w 降序排列的算法访问的程序代码是没有问题的。(网上的回溯法我看实质上都是结合贪心做的)。但是很明显可以看到在按随机算法访问序列那里,程序输出的结果并不准确。个人分析原因是因为在随机序列算法访问节点时,未对程序进行排序,则计算bound()函数并未算对,导致右子树的剪枝不正确。

不太知道怎么改,有没有大神帮忙修改一下~

回溯法求解0-1背包问题相关推荐

  1. 回溯法 —— 求解0/1背包问题(剪枝)

    0/1背包问题 题目描述: 有n个重量分别为w1,w2,-,wn的物品(物品编号为1~n),它们的价值分别为v1,v2,-,vn,给定一个容量为W的背包.设计从这些物品中选取一部分物品放入该背包的方案 ...

  2. 分枝限界法求解0/1背包问题

    问题描述 有n个重量分别为{w1,w2,-,wn}的物品,它们的价值分别为{v1,v2,-,vn},给定一个容量为W的背包. 设计从这些物品中选取一部分物品放入该背包的方案,每个物品要么选中要么不选中 ...

  3. 回溯法求解0 1背包的优化

    优化方法:  剪枝一:可以进行剪枝,因为很多情况是没有意义的,当重量大于背包容量的时候,没有必要对剩下的物品再来决策了. 剪枝二:将剩下的所有物品都选取其总价值也没有目前已经求得的方案的价值还大的话, ...

  4. 01背包问题【回溯法求解】通俗易懂,适合小白

    本人此时还是一名研一的小菜鸡,刚学会了这个算法的基本概念,来总结一下,谁知道今后的我再看到这篇自己写的博客的时候会不会笑出来,哈哈哈哈哈哈哈哈,所以吗,错了的化大佬们评论指正就好了. 还有系列文章动态 ...

  5. 回溯法求解0-1背包问题(细节分析)

    回溯法求解0-1背包问题(细节分析) 论temp数组的必要性和判断cv>bestv的不必要性 回溯法 应用回溯法求解问题时,首先应明确定义问题的解空间,该解空间应至少包含问题的一个最优解.例如, ...

  6. 【算法分析】实验 4. 回溯法求解0-1背包等问题

    目录 实验内容 实验目的 实验结果 步骤1:描述与分析 步骤2:策略以及数据结构 步骤3 步骤4 步骤5 步骤6 实验总结 实验内容 本实验要求基于算法设计与分析的一般过程(即待求解问题的描述.算法设 ...

  7. java背包算法回溯法_【算法分析】实验 4. 回溯法求解0-1背包等问题

    [TOC] 实验内容 本实验要求基于算法设计与分析的一般过程(即待求解问题的描述.算法设计.算法描述.算法正确性证明.算法分析.算法实现与测试),通过回溯法的在实际问题求解实践中,加深理解其基本原理和 ...

  8. 回溯法求解N皇后问题(Java实现)

    回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并以此慢慢地扩大问题规模,迭代地逼近最终问题的解.这种迭代类似于穷举并且是试探性的,因为当目前的可 ...

  9. 分枝定界法解0/1背包问题

    分枝定界法解0/1背包问题 关键词:分支定界.0-1背包 分枝定界法简介 分枝定界法按照树形结构来组织解空间,展开节点后,有两种策略: 策略一.把节点加入 FIFO 队列当中: 策略二.把节点加入到堆 ...

最新文章

  1. 范围元【2013 GDCPC】有为杯 广东ACM省赛小总结
  2. 文巾解题 136. 只出现一次的数字
  3. word怎么设置图片编号(图片下标,图片标签,图片序号,图片注释,题注)(交叉引用)
  4. centos7 python3安装numpy_centos 7 下安装numpy、scipy等python包
  5. pupload 文件分块 php,基于Plupload实现Base64分割的文件上传方案
  6. DNS协议及客户端实现
  7. linux 汽车仪表软件架构,基于嵌入式Linux的汽车全数字仪表界面的设计
  8. 线程的简单理解,适用于初接触的小白,另类例子讲解,通俗易懂
  9. 05-信息管理系统--主页面显示当前用户实现退出功能实现
  10. 苏宁!你还挺得过去吗?(苏宁大幅裁员)
  11. 【文化课每周学习记录】2019.3.17——2019.3.23
  12. 解空间树及其相关算法
  13. 计算机奖项含金量排名,2019五大学科竞赛含金量排名
  14. 金桔蓝牙LoRa主被动一体定位系统原理
  15. css bottom属性 使元素位置相对固定
  16. 北京程序员小哥哥的故事
  17. 2021微信大数据挑战赛正式启动报名!
  18. 微信小程序 使用map组件 地图获取位置、移动选点、逆地址解析
  19. 使用UDP实现群聊聊天室
  20. VS2019不能安装的WIN10更新问题

热门文章

  1. JAVA毕设项目网上书店管理系统(java+VUE+Mybatis+Maven+Mysql)
  2. kali linux怎么远程桌面,适用于kali linux的远程桌面开启方法(从windows xp 远程登录到kali linux )...
  3. STC12C5A60S2系列单片机PCA时钟源设置
  4. 两个外企常用的电面网站
  5. 鸿蒙开发(2)---Button组件
  6. opencv通过mask取目标纯色背景图
  7. vue-element-admin 的使用记录(三)
  8. 物联网是大家都看好的创业方向
  9. 发生了Post错误:错误代码40005,微信返回错误信息:invalid file type
  10. iOS开发底层之KVO探索下 -18