博客
关于我
好理解的基于二叉树的0-1背包求解问题
阅读量:495 次
发布时间:2019-03-07

本文共 2784 字,大约阅读时间需要 9 分钟。

问题描述:

给定n(n<=100)种物品和一个背包。物品i的重量是wi,价值为vi,背包的容量为C(C<=1000)。问:应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。

输入样例1:

在这里给出一组输入。例如:

5 10
2 6
2 3
6 5
5 4
4 6

输出样例1:

15

输入样例2:

6 60

15 32
17 37
20 46
12 26
9 21
14 30

输出样例2:

134

———————————————————————

建立一个二叉树,我们约定左结点表示选择装入物品,右节点表示不装入物品。

假设有5个物品,

物品重量是{2, 2, 6, 5, 4}
对应价值是{6, 3, 5, 4, 6}
约定所有物品装入背包后,背包的总重量不超过10

============================

对于第一个物品,我们可以选择装入或者不装入
若装入,总重量weigth = 2, 总价值value = 6
若不装入,总重量weigth = 0, 总价值value = 0

============================

对于第二个物品,我们可以选择装入或者不装入
若第一个物品已经装入,则
若装入第二个物品,总重量weigth = 4, 总价值value = 9
若不装入第二个物品,总重量weigth = 2, 总价值value = 6

若第一个物品没有装入,则

若装入第二个物品,总重量weigth = 2, 总价值value = 3
若不装入第二个物品,总重量weigth = 0, 总价值value = 0

============================

… … … … …

依次类推,我们可以构造出这样的二叉树(局部)

在这里插入图片描述

那么可以知道背包里的物品最大值在二叉树的叶子结点那里。

#include
#include
using namespace std;//不要向结构体直接定义默认值,可以通过一个函数进行基本的初始化typedef struct TreeNode{ long long int val; long long int weight; bool left;//是否已经访问左子树 bool right;//是否已经访问右子树 TreeNode *LChild;//左节点 TreeNode *RChild;//右节点 TreeNode *Parent; //父结点}TreeNode;TreeNode *init(TreeNode *node){ node->weight = 0;//记录当前结点已经装的重量和价值(边装边计算) node->val = 0; node->left = false;//是否已经访问左子树 node->right = false;//是否已经访问右子树 node->LChild = NULL;//左节点 node->RChild = NULL;//右节点 node->Parent = NULL; //父结点 return node;}int n, c;//个数,规定总重量long long int MAX=0;TreeNode *addNode(TreeNode *parented, int w, int val){ TreeNode *node=(TreeNode *)malloc(sizeof(TreeNode)); node = init(node); // node.data = data;// if(parented->weight+w <= c){ //可以装 node->weight = w + parented->weight; //记录已有重量 node->val = val + parented->val; node->Parent = parented; }else{ node=NULL;//装不下,返回空 } return node;}int main(int argc, char const *argv[]){ TreeNode *head=(TreeNode *)malloc(sizeof(TreeNode)); //w记录重量,p记录价值,(i+1)表示第几个物品(i=0是第一个物品,w[0], p[0]表示第一个物品的重量和价值) (0<=i
>n>>c; //初始化数组 for(i=0; i
>w[i]>>p[i]; } head = init(head); i=0; while(1){ if(head->left&&head->right&&head->Parent==NULL){ //头结点已经将左右子树访问完,退出循环 cout<<"结束"<
left&&head->right){ //子节点都访问了,就回退 cout<<"回退"<
Parent; continue; } if(i>=n||head->weight>=c){ //加完数据了或者背包已经装满了 cout<<"加完数据了或者已经装满了"<
val)MAX = head->val;//保存最大值 head->left = true; head->right = true; continue; } if(!head->left){ //左边没有插入过 cout<<"加左结点 i = "<
<
left = true;//表名我已经访问当前结点的左结点 head->LChild = addNode(head, w[i], p[i]);//表示将当前结点插入 if(head->LChild!=NULL){ //左边插入成功 i++;//下一个数据 head = head->LChild; } }else if(!head->right){ //右边没有插入过 cout<<"加右结点 i = "<
<
right = true;//表名我已经访问当前结点的右结点 head->RChild = addNode(head, 0, 0);//表示跳过当前物品的装入,去下一个物品 if(head->RChild!=NULL){ //右边边插入成功 i++; head = head->RChild; } } } //通过先序遍历,即可获得背包中物品的最大总价值。也可给出装入物品的序列 cout<
<

在这里插入图片描述

在这里插入图片描述

转载地址:http://xjccz.baihongyu.com/

你可能感兴趣的文章
Navicat向sqlserver中插入数据时提示:当 IDENTITY_INSERT 设置为 OFF 时,不能向表中的标识列插入显式值
查看>>
Navicat因导入的sql文件中时间数据类型有参数而报错的原因(例:datetime(3))
查看>>
Navicat如何连接MySQL
查看>>
navicat导入.sql文件出错2006- MySQLserver has gone away
查看>>
Navicat导入海量Excel数据到数据库(简易介绍)
查看>>
Navicat工具Oracle数据库复制 or 备用、恢复功能(评论都在谈论需要教)
查看>>
Navicat工具中建立数据库索引
查看>>
navicat工具查看MySQL数据库_表占用容量_占用空间是多少MB---Linux工作笔记048
查看>>
navicat怎么导出和导入数据表
查看>>
Navicat怎样同步两个数据库中的表
查看>>
Navicat怎样筛选数据
查看>>
Navicat报错connection is being used
查看>>
Navicat报错:1045-Access denied for user root@localhost(using passwordYES)
查看>>
Navicat控制mysql用户权限
查看>>
navicat操作mysql中某一张表后, 读表时一直显示正在载入,卡死不动,无法操作
查看>>
Navicat连接mysql 2003 - Can't connect to MySQL server on ' '(10038)
查看>>
Navicat连接mysql数据库中出现的所有问题解决方案(全)
查看>>
Navicat连接Oracle出现Oracle library is not loaded的解决方法
查看>>
Navicat连接Oracle数据库以及Oracle library is not loaded的解决方法
查看>>
Navicat连接sqlserver提示:未发现数据源名并且未指定默认驱动程序
查看>>