C语言分支限界法求解01背包问题

news/2024/7/20 21:16:30 标签: c语言, 深度优先, 算法

分支限界法是一种求解优化问题的算法,针对01背包问题,它可以通过在搜索过程中剪枝,减少搜索空间的大小,提高算法的效率。

具体来说,分支限界法会将当前状态下的可行解集合分成若干个子集,每个子集代表一条搜索路径,然后根据某种启发式策略(如最大价值优先、最小重量优先等)对这些子集进行排序,选择价值最大/重量最小的子集进行扩展,将其分成若干个子集,再重复上述过程,直到找到最优解或者搜索结束。

在求解01背包问题时,分支限界法每次扩展节点时,会判断当前节点能否产生更优的解,如果不能,就进行剪枝,减少搜索空间。例如,如果当前节点已经超出了背包的容量限制,就可以直接剪枝,不再继续扩展。在搜索过程中,分支限界法还会维护一个上界,即当前可行解集合中的最优解,如果当前节点的下界已经小于上界,也可以直接剪枝,不再继续扩展。

分支限界法是一种高效、精确的求解优化问题的算法,但需要注意的是,它并不保证一定能找到最优解,因为搜索空间较大时,其时间复杂度可能会非常高。

代码:

#include <stdio.h>
#include <stdlib.h>

#define MAX_N 1000  // 最大物品数量
#define MAX_W 1000  // 最大背包容量

int n;  // 物品数量
int w[MAX_N];  // 物品重量
int v[MAX_N];  // 物品价值
int c;  // 背包容量
int maxv;  // 最大价值
int curw;  // 当前背包重量
int curv;  // 当前背包价值
int bestv[MAX_W];  // bestv[i]表示当前索引为i时,背包容量为i时的最大价值

// 计算以j为索引、背包容量为c的情况下,能够获得的最大价值
int bound(int j, int c) {
    int b = curv;
    int leftw = c - curw;
    while (j < n && leftw >= w[j]) {
        leftw -= w[j];
        b += v[j];
        j++;
    }
    if (j < n) {
        b += leftw * v[j] / w[j];
    }
    return b;
}

// 搜索第i个物品是否放入背包
void dfs(int i) {
    if (i == n) {  // 达到叶子节点,更新最大价值
        maxv = curv;
        return;
    }
    // 不选第i个物品
    bestv[i+1] = bound(i+1, c);  // 计算下一个物品的最大价值
    if (bestv[i+1] < maxv) {  // 如果最大价值都小于当前最大价值,直接返回
        return;
    }
    dfs(i+1);
    // 选第i个物品
    if (curw + w[i] <= c) {  // 可以放入背包
        curw += w[i];
        curv += v[i];
        if (curv > maxv) {  // 更新最大价值
            maxv = curv;
        }
        bestv[i+1] = bound(i+1, c);  // 计算下一个物品的最大价值
        if (bestv[i+1] > maxv) {  // 如果最大价值比当前最大价值大,继续搜索
            dfs(i+1);
        }
        curw -= w[i];  // 回溯
        curv -= v[i];
    }
}

int main() {
    // 读入数据
    scanf("%d%d", &n, &c);
    for (int i = 0; i < n; i++) {
        scanf("%d%d", &w[i], &v[i]);
    }
    // 初始化
    maxv = curv = 0;
    curw = 0;
    bestv[0] = bound(0, c);
    // 搜索
    dfs(0);
    // 输出结果
    printf("%d\n", maxv);
    return 0;
}

分支限界法的思路如下:

  1. 按照某种规则先对问题求出一个下界,把问题分成可行和不可行两种情况。对于可行的情况,可以计算出对应的最优解的上界(贪心法、动态规划等)。
  2. 依次搜索所有可能的解,在搜索过程中,利用计算出的上界剪枝,即当某个节点的上界小于当前最优解时,可以直接返回上一层,省略掉这个分支。
  3. 在搜索过程中,记录当前的最优解,并不断更新。当达到叶子节点,即搜索结束时,返回最优解。

对于01背包问题,每个节点有两种情况,即选或不选当前物品。对于每个节点,可以计算出剩余物品的最大价值,从而计算出当前节点可以达到的最大价值(上界)。用一个数组bestv记录每个节点的最大价值,如果当前节点的上界小于当前最优解,直接返回;如果当前节点的最大价值比当前最优解大,继续搜索。在搜索过程中,使用变量curwcurv记录当前的背包重量和价值,变量maxv记录当前的最大价值。


http://www.niftyadmin.cn/n/5208175.html

相关文章

12个最佳WordPress投票插件

您是否正在为您的网站寻找WordPress投票插件&#xff1f; WordPress投票插件可让您轻松地在您的网站上进行民意调查&#xff0c;用户可以投票。这是在收集见解的同时建立用户参与度的有效策略。 在本文中&#xff0c;我们精心挑选了最好的WordPress投票插件&#xff0c;可帮助…

mac 终端配置

Mac iTerm2 配置 安装 brew install iTerm2安装完成之后&#xff0c;需要重新打开终端&#xff0c;既可以看见安装 iTerm2 的效果。 iTerm2 美化 使用 oh-my-zsh 美化 iTerm2 终端 安装 brew install wget sh -c "$(wget https://raw.github.com/ohmyzsh/ohmyzsh/mast…

微信小程序bindtap和catchtap的区别?

子元素用bindtap绑定事件后&#xff0c;执行的时候&#xff0c;会冒泡到父元素&#xff08;触发父亲元素上绑定的bindtap事件&#xff09; 如果不想冒泡到父元素&#xff0c;可以用catchtap代替 bindtap事件绑定不会阻止冒泡事件向上冒泡 catchtap事件绑定可以阻止冒泡事件向上…

基于51单片机车载空调系统设计proteus仿真+源程序)

一、系统方案 1、本设计采用这51单片机作为主控器。 2、DS18B20采集温度值送到液晶1602显示。 3、按键设置报警值。 4、温度控制风扇档位。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 /T0初始化*/ void init_t0() { //TMOD0x01;//定时器…

广告机/商业显示屏_基于MT8788安卓主板方案

安卓主板在广告机领域扮演着重要的角色。无论是在商场、车站、酒店、电梯、机场还是高铁站&#xff0c;LED广告机广泛应用&#xff0c;并通过不同方式进行播放和管理。 广告机/商业显示屏_基于MT8788安卓主板方案 基于MT8788安卓主板方案的广告机采用了联发科MT8788八核芯片方案…

JavaWeb——感谢尚硅谷官方文档

JavaWeb——感谢尚硅谷官方文档 XML一、xml简介二、xml的语法1、文档申明2、xml注释3、xml元素4、xml属性5、xml语法规则 三、xml解析技术1、使用dom4j解析xml Tomcat一、JavaWeb的概念二、web资源的分类三、常见的web服务器四、Tomcat的使用1、安装2、Tomcat的目录介绍3 启动T…

tp8 使用rabbitMQ(3)发布/订阅

发布/订阅 当我们想把一个消息&#xff0c;发送给 多个消费者的时候&#xff0c;我们把这种模式叫做发布/订阅模式&#xff0c;比如我们做两个消费者&#xff0c;其中一个消费者把消息写入磁盘中&#xff0c;别一个消费者把消息结果输出到屏幕上&#xff0c;就要用到发布订阅模…

【前端】必学知识ES6 1小时学会

1.ES6概述 2.let和const的认识 3.let、const、var的区别 4.模板字符串 5.函数默认参数 6.箭头函数【重点】 ​编辑7.对象初始化简写以及案例分析 【重点】 8.对象解构 8.对象传播操作符 9.对象传播操作符案例分析 ​编辑 10.数组Map 11.数组Reduce 12.NodeJS小结 …