0-1背包-回溯法
时间:2022-04-22
本文章向大家介绍0-1背包-回溯法,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
算法描述:
0-1背包的回溯法,与装载问题的回溯法十分相似。在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树。当右子树中有可能包含最优解时才进入右子树进行搜索。否则将右子树剪去。
计算右子树上界的更好算法是:
将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包。
算法实现:
由Bound函数计算当前节点处的上界。
类Knap的数据成员记录解空间树的节点信息,以减少参数传递及递归调用所需的栈空间。
在解空间树的当前扩展结点处,仅当要进入右子树时,才计算上界bound,以判断是否可将右子树剪去。
进入左子树时不需要计算上界,因为它与其父节点的上界相同。
算法实现:(代码有点小问题,正在修改中)
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
template <class Typew,class Typep>
class Knap{
friend Typep Knapsack(Typep *,Typew *,Typew,int);
private:
Typep Bound(int i);
void Backtrack(int i);
Typew c;//背包容量
int n;//物品数
Typew * w;//物品重量数组
Typep * p;//物品价值数组
Typew cw;//当前重量
Typep cp;//当前价值
Typep bestp;//当前最优价值
};
template <class Typew,class Typep>
void Knap<Typew,Typep>::Backtrack(int i)
{
if(i>n)//到达叶子
{
bestp = cp;
return;
}
if(cw+w[i] <= c)//进入左子树
{
cw += w[i];
cp += p[i];
Backtrack(i+1);
cw -= w[i];
cp -= p[i];
}
if(Bound(i+1)>bestp)//进入右子树
Backtrack(i+1);
}
template <class Typew,class Typep>
Typep Knap<Typew,Typep>::Bound(int i)//计算上界
{
Typew cleft = c- cw;//剩余容量
Typep b = cp;
while(i<=n && w[i]<=cleft)//以物品单位重量价值递减序装入物品
{
cleft -= w[i];
b += p[i];
i++;
}
//装满背包
if(i<=n)
b+=p[i]*cleft/w[i];
return b;
}
class Object
{
friend int Knapsack(int *,int *,int,int);
public:
int operator <= (Object a)const
{
return (d >= a.d);
}
private:
int ID;
float d;
};
int compare (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
template <class Typew,class Typep>
Typep Knapsack(Typep p[],Typew w[],Typew c,int n)
{
int i;
//初始化
int W = 0;
int P = 0;
Object* Q = new Object[n];
for(i=0;i<n;i++)
{
// cout<<p[i]<<" "<<w[i]<<endl<<"-------------------------"<<endl;
Q[i].ID = i;
Q[i].d = 1.0*p[i]/w[i];
// cout<<Q[i].ID<<" "<<Q[i].d<<endl<<"----------------------"<<endl;
P += p[i];
W += w[i];
// cout<<P<<" "<<W<<endl<<endl;
}
if(W<=c)
return P;//装入所有物品
//依物品单位重量价值排序
qsort (Q,n, sizeof(int), compare);
Knap<Typew,Typep> K;
K.p = new Typep [n+1];
K.w = new Typew [n+1];
for(i =1;i<=n;i++)
{
K.p[i] = p[Q[i-1].ID];
K.w[i] = w[Q[i-1].ID];
}
K.cp = 0;
K.cw = 0;
K.n = n;
K.bestp = 0;
K.Backtrack(1);
// cout<<K.bestp<<endl;
delete [] Q;
delete [] K.w;
delete [] K.p;
return K.bestp;
}
int main()
{
int p[4] = {9,10,7,4};
int w[4]= {3,5,2,1};
int num = Knapsack(p,w,7,4);
cout<<num<<endl;
return 0;
}
- VUE 入门基础(3)
- ASP.NET MVC 2 转换工具
- 使用Sysinternals工具定时休眠Windows Server 2008 R2
- Android中BroadcastReceiver广播
- 启用Windows 7/2008 R2 XPS Viewer
- Spring历史版本变迁和如今的生态帝国
- Android中Services之异步IntentService
- 使用GitHub搭建个人博客
- 这个用来玩儿游戏的算法,是谷歌收购DeepMind的最大原因
- asp.net安全检测工具 --Padding Oracle 检测
- Android中Services简析
- VUE 入门基础(2)
- VUE 入门基础(1)
- AndroidManifest.xml配置文件 android.theme大全权限设置Android Permission中英对照
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- [mongodb] mongo常用字段类型
- 无意间发现一个好用的视频转换gif图片的开源框架
- 解读闭包,这次从ECMAScript词法环境,执行上下文说起
- 额度模型(一)
- GitHub Actions使用入门
- freeswitch笔记(9)-esl outbound中如何放音采集按键?
- react childern添加事件
- Spring事务的传播行为案例分析
- ThreadLocal与Java引用类型(文末含福利)
- GitLab 12 跨版本 13 升级
- 打破你的认知!Java空指针居然还能这样玩,90%人不知道…
- Android 原生 SQLite 数据库的一次封装实践
- Window常用账号密码修改(Git)
- 高通AI研究院|高效网络设计|结构化卷积分解
- tomcat调优 tomcat配置优化