01背包问题-队列分支限界法-C++

0-1背包问题-队列分支限界法

问题描述:

给定n种物品和一个背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?对于给定的n种物品的重量和价值,以及背包的容量,计算可装入背包的最大价值。

算法设计过程:

考虑使用队列分支限界法来解决来解决0-1背包问题,对于每一个物品,我们都有选或者不选两种情况,因此该问题的解空间为一颗子集树。

要采用队列来求解该问题,对于队列中的每一个节点,都要维护当前节点所选择的物品集合,同时维护当前节点的总价值和容量,为剪去不可行解和优化搜索过程做准备。

对于该问题,我们在使用队列分支限界的搜索过程,在处理当前节点时,可以考虑对左右儿子进行约束和限界:
对于该节点的左儿子,我们要考虑其是否满足约束,具体的,我们要考虑当前背包剩余空间能否装下这个物品,也就是当前的总重加上该物品的总量要小于背包总容量时我们才考虑进入左儿子节点。否则左儿子就是一个不可行解,直接跳过即可。
对于该节点的右儿子,我们考虑设计一个限界函数bound来限制进入右儿子的条件,在搜索过程我们维护一个当前的最优解,我们要通过计算进入右子树后有没有可能得到更优的解,只有右儿子包含最优解时我们才选择进入。具体的,设cv是当前的价值,我们考虑将该物品跳过后的最优价值为r,对于当前的最优解bstv,若是\cv+r<=bstv时,我们便考虑剪去右子树,为了更好的实现,我们需要在搜索之前对物品按单位重量价值进行排序,然后依次装入物品,直到装不下时,再装入该物品的一部分而装满背包,由此得到右子树的上界bound。

对于该问题我们的具体算法流程:
1.对所有物品按单位重量价值从大到小进行排序。
2.初始化队列,加入初始的节点,这里以第一个物品作为根节点加入。
3.当队列不为空时,每次从队列中取出一个节点的进行扩展。
4.如果左儿子是可行节点,即满足约束条件时,如果该结点的价值大于最优解,则更新最优解,同时将该节点加入队列。
5.对于扩展节点的右儿子,当其满足限界函数时才将其加队列中。
6.当队列为空时,说明搜索过程已经结束,直接返回最优解即可。

流程图:
在这里插入图片描述

代码:

#include <bits/stdc++.h>
using namespace std;

struct Obj{ // 物品
    int id; 
    int w;
    int val;
    bool operator<(Obj &obj){
        return val * obj.w > obj.val * w;
    }
};

struct Node {
    int dep; // 深度,第几层就是处理第几个物品
    int cv; /// 当前价值
    int cw; // 当前容量
    vector<int>x; // 解向量
    
    Node(int dep,int cv, int cw, vector<int>x):dep(dep), cv(cv), cw(cw), x(x) {} 

    friend ostream& operator<<(ostream& os, const Node& p){
        cout << "dep:" << p.dep << " cv:" << p.cv << " cw:" << p.cw;
        cout << " x:";
        for(int i:p.x)cout << i << ' ';
        return os;
    };  

};

struct Whopxx{
    int n; // 物品数量
    vector<Obj>vt; // 物品
    int sum; // 背包大小

    vector<int>bstx; // 最优解
    int bstv;
    
    Whopxx(int n,int sum, vector<int>w, vector<int>p):n(n), sum(sum) {
        bstx.resize(n + 1);
        bstv = 0;
        vt.resize(n + 1);
        for(int i = 1; i <= n; i++){
            vt[i] = {i, w[i], p[i]};
        }
        sort(vt.begin() + 1, vt.end()); // 按单价从大到小排序
    }

    void work(){
        queue<Node> q;
        q.push(Node(1, 0, 0, {})); // 第一个物品开始做选择
        while(q.size()){
            Node node = q.front(); q.pop();
            cout << node << " bound:" << Bound(node) << " bstv:" << bstv << endl;
            int i = node.dep;
            if(i > n || node.cw == sum){ // 到达叶子结点或背包已满
                if(node.cv > bstv) update(node); // 更新最大值
                continue;
            }
            
            auto [id, w, val] = vt[i];
            if(node.cw + w <= sum){ // 左儿子满足约束
                Node lnode = add(node, vt[i]);
                q.push(lnode);
                if(lnode.cv > bstv) update(lnode);
            }

            if(Bound(node) > 1.0 * bstv){ // 右儿子满足限界
                Node rnode = uadd(node);
                q.push(rnode);
            }
            
        }
    }

    double Bound(Node node){ // 限界函数
        int rw = sum - node.cw; // 剩余容量
        int i = node.dep + 1;
        double b = node.cv;
        while(i <= n && vt[i].w <= rw){
            rw -= vt[i].w;
            b += vt[i].val;
            i++;
        }
        if(i <= n){
            b += vt[i].val * 1.0 / vt[i].w * rw;
        }
        return b;
    }

    Node add(Node node, Obj obj){
        node.cv += obj.val;
        node.cw  += obj.w;
        node.x.push_back(obj.id);
        node.dep += 1;
        return node;
    }

    Node uadd(Node node){
        node.dep += 1;
        return node;
    }

    void update(Node node){
        bstx = node.x;
        bstv = node.cv;
    }
};


int main(){ 
    freopen("input.txt","r", stdin);
    freopen("output.txt", "w", stdout);
    
    int n, c; // 物品数量,背包容量
    cin >> n >> c;
    vector<int>w(n + 1);
    vector<int>p(n + 1);
    for(int i = 1; i <= n; i++) cin >> p[i];
    for(int i = 1; i <= n; i++) cin >> w[i];

    Whopxx wx(n, c, w, p);
    wx.work();
    vector<int>ans(n + 1);
    for(int i:wx.bstx) ans[i] = 1;
    cout << wx.bstv << endl;
    for(int i = 1; i <= n; i++){
        cout << ans[i] << ' ';
    }

    fclose(stdin);
    fclose(stdout);
    return 0;
}
/*
4 7
9 10 7 4
3 5 2 1


3 30
45 25 25
16 15 15

4 15
10 10 12 18
2 4 6 9

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


4 10
40 42 25 12
4 7 5 3
*/

实验测试结果及分析:
测试数据:
input.txt
在这里插入图片描述

通过运行程序得到:
output.txt
在这里插入图片描述

在该输出结果中,cv是当前节点的物品价值总和,cw是当前总重,bound是进入右子树后的最大值,bstv是进行到当前节点的全局最优解得值,形象的可以用如下图来表示该搜索过程:
在这里插入图片描述

最终我们得到最优解即选择物品1和物品3装入背包,得到的最优总价值为65。

复杂度分析:限界函数的时间复杂度为O(n),在最坏的情况下有2^n个右儿子结点需要计算上界,所以计算需要的最坏情况下的时间复杂度为O(n2 ^n)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/779363.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

17-JS封装:工具类方法

目录 一、extend方法 二、添加一些工具类方法&#xff1a;$.xxx() 实现1&#xff1a; 实现2&#xff1a; 一、extend方法 jQuery.fn.extend jQuery.extend function(...args){let target,source[];source[...args];//判断2种情况 //$.extend({}) -->给$添加属性//$.…

算法金 | 欧氏距离算法、余弦相似度、汉明、曼哈顿、切比雪夫、闵可夫斯基、雅卡尔指数、半正矢、Sørensen-Dice

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 抱个拳&#xff0c;送个礼 在算法模型构建中&#xff0c;我们经常需要计算样本之间的相似度&#xff0c;通常的做法是计算样本之间的距…

源码航行阅读目录

&#x1f3c0; 前言 在准备面试和学习的过程中&#xff0c;我阅读了比较多的源码&#xff0c;比如 JUC、Spring、MyBatis&#xff0c;收获了很多代码的设计思想&#xff0c;也对平时调用的 API 有了更深入的理解&#xff1b;但过多散乱的笔记给我的整理复习带来了比较大的麻烦…

基于Java技术的人事管理系统

你好&#xff0c;我是专注于计算机科学领域的小野。如果你对人事管理系统感兴趣或有相关需求&#xff0c;欢迎私信交流。 开发语言&#xff1a; Java 数据库&#xff1a; MySQL 技术&#xff1a; B/S模式、Java技术、SpringBoot 工具&#xff1a; Eclipse、MySQL、浏览…

【linux学习---1】点亮一个LED是多么的困难!!!

文章目录 1、原理图找对应引脚2、IO复用3、IO配置4、GPIO配置5、GPIO时钟使能6、总结7、编程8、编译9、链接10、格式转换11、反汇编&#xff08;查看用&#xff09;12、使用Makefile操作13、代码烧写14、代码验证 1、原理图找对应引脚 从上图 可以看出&#xff0c; 蜂鸣器 接到…

Photoshop属于什么软件 Photoshop缓存文件清理 Mac清理PS缓存 苹果电脑ps内存满了怎么清理

对于所有热爱使用Adobe Photoshop的Mac用户来说&#xff0c;这款软件无疑是创意工作的强大助手。但是&#xff0c;随着时间的积累&#xff0c;你可能会发现Photoshop开始变得有点慢&#xff0c;反应迟钝。这通常是因为Photoshop的缓存和临时文件堆积&#xff0c;占用了宝贵的系…

刷题之买股票的最佳时机(leetcode)

买股票的最佳时机 动态规划入门题。 最简单的模拟式解法&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {//也可以换一种思路&#xff0c;因为只交易一次&#xff0c;那么找出股票最便宜的时候买入&#xff0c;最贵的时候卖出&#xff…

每日一题~ (判断是否是合法的出栈序列)

大概的题意&#xff1a; 将 1-n 按照顺序进栈&#xff0c;问 输入的序列是否是合法的出栈序列。 遍历序列&#xff0c;如果当前这个值a小于 栈顶的值&#xff0c;说明它还未进栈&#xff08;因为我们是按照顺序进栈的&#xff09;&#xff0c;所以我们将 一些元素进栈&#xff…

uniapp 封装请求

新建request文件夹 下新建index.js 和index.js 或者创建units文件放入index.js 和api文件夹放入index.js(api.js)//看公司规范 1. index.js // 全局请求封装 // const base_url http://localhost:8080/devapi var base_url process.env.NODE_ENV development ? http://…

Studying-代码随想录训练营day27| 贪心算法理论基础、455.分发饼干、376.摆动序列、53.最大子序和

第27天&#xff0c;贪心开始&#xff01;(ง •_•)ง&#x1f4aa;&#xff0c;编程语言&#xff1a;C 目录 贪心算法理论基础 贪心的套路 贪心的一般解题步骤 总结 455.分发饼干 376.摆动序列 53.最大子序和 总结 贪心算法理论基础 什么是贪心&#xff1f;—— 贪…

自动化设备上位机设计 三

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 using SqlSugar;namespace 自动化上位机设计 {public partial class Form1 : Form{SqlHelper sqlHelper new SqlHelper();SqlSugarClient dbContent null;bool IsRun false;int Count 0;public Form1(){Initializ…

SpringBoot新手快速入门系列教程五:基于JPA的一个Mysql简单读写例子

现在我们来做一个简单的读写Mysql的项目 1&#xff0c;先新建一个项目&#xff0c;我们叫它“HelloJPA”并且添加依赖 2&#xff0c;引入以下依赖&#xff1a; Spring Boot DevTools (可选&#xff0c;但推荐&#xff0c;用于开发时热部署)Lombok&#xff08;可选&#xff0c…

Google Earth Engine(GEE)——在控制台打印出来所选区域的缩略图

结果 函数 ui.Thumbnail(image, params, onClick, style) A fixed-size thumbnail image generated asynchronously from an ee.Image. Arguments: image (Image, optional): The ee.Image from which to generate the thumbnail. Defaults to an empty ee.Image. param…

简单分享下python多态

目录&#xff1a; 一、多态是啥嘞&#xff08;龙生九子各有不同&#xff0c;这就是多态&#xff09; 二、基础的实例 三、多态的优势与应用场景 四、深入理解 一、多态是啥嘞&#xff08;龙生九子各有不同&#xff0c;这就是多态&#xff09; 多态&#xff08;Polymorphism&…

Laravel5+mycat 报错 “Packets out of order”

背景 近期对负责项目&#xff0c;配置了一套 主从复制的 MySQL 集群 使用了中间件 mycat 但测试发现&#xff0c;替换了原来的数据连接后&#xff0c;会出现 Packets out of order 的报错 同时注意到&#xff0c;有的框架代码中竟然也会失效&#xff0c;比如 controller 类中&…

Mac电脑iTerm2 如何设置无限滑动

1.打开iTerm2应用 2.打开偏好设置 3.选中Profiles -> Terminal 4.选择Unlimited scrollback

Linux开发讲课33---线程实现与线程控制步骤简析

线程概述 进程是系统中程序执行和资源分配的基本单位。 每个进程都拥有自己的数据段、代码段和堆栈段&#xff0c;这就造成了进程在进行切换等操作时都需要有比较负责的上下文切换等动作。为了进一步减少处理机的空转时间支持多处理器和减少上下文切换开销&#xff0c;进程在演…

Ollama+OpenWeb UI搭建最简单的大模型交互界面

Open WebUI是一个专为大型语言模型&#xff08;LLMs&#xff09;设计的Web用户界面。这个界面提供了一个直观、响应迅速且易于使用的平台&#xff0c;使用户能够与本地运行的语言模型进行交互&#xff0c;就像与云服务中的模型交互一样。可以非常方便的调试、调用本地模型。你能…

Interpretability 与 Explainability 机器学习

「AI秘籍」系列课程&#xff1a; 人工智能应用数学基础人工智能Python基础人工智能基础核心知识人工智能BI核心知识人工智能CV核心知识 Interpretability 模型和 Explainability 模型之间的区别以及为什么它可能不那么重要 当你第一次深入可解释机器学习领域时&#xff0c;你会…

第十四届蓝桥杯省赛C++B组G题【子串简写】题解(AC)

题目大意 给定字符串 s s s&#xff0c;字符 a , b a, b a,b&#xff0c;问字符串 s s s 中有多少个 a a a 开头 b b b 结尾的子串。 解题思路 20pts 使用二重循环枚举左端点和右端点&#xff0c;判断是否为 a a a 开头 b b b 结尾的字符串&#xff0c;是则答案加一…