分支限界法实现最优装载c++_分支限界法

一、方法概述

1、基本思想

(1)什么事分支限界法?

在解空间树中,广度优先遍历(BFS)或最佳优先方式搜索最优解,利用部分最优解的信息,裁剪那些不能得到最优解的子树以提升搜索效率。

(BFS or 最佳优先方式搜索+剪枝)

a2cda61add97a4fb9cdc719154fcb16f.png

(2)搜索策略:

step1:在扩展节点处(当前的搜索位置,一个活结点),先生成其所有的儿子结点(分支),然后再从当前的活结点选择下一个扩展结点。

step2:为了有效的选择下一扩展结点,以加速搜索的进程,在每一活结点处,计算一个函数值(优先值),并根据这些已经计算出来的函数值,从当前活结点表中选择一个最有利的节点作为扩展结点,使搜索朝着解空间树上的最优解的分支推进,以便尽快的找出一个最优解。(关于解空间树、活结点、拓展结点在之后的文章分享)

2、与回溯法区别(回溯法之后的文章分享)

(1)求解目标不同

回溯法:找出解空间树满足约束条件的所有解

分支限界法:尽快的找出满足约束条件的一个解

(感觉有点类似于动态规划和贪心算法的差别,同样之后陆续分享)

(2)搜索方法不同

回溯法:DFS深度优先搜索

分支限界法:BFS宽度优先 or 最佳优先方法搜索

(3)对扩展结点的扩展方式不同

分支限界法:每一个活结点只有一次机会成为扩展节点。活结点一旦成为扩展结点,就一次性产生全部的儿子结点。

(4)存储空间的要求

分支限界法对存储空间的要求比回溯法大得多,因此当内存容量有限时,回溯法成功的可能性更大。

3、求解步骤

step1:定义解空间(对解编码)

step2:确定解空间的树结构

step3:按照BFS等方式搜索:

a.每个活结点仅有一次机会变成扩展结点;

b.由扩展结点生成一步可达的新结点;

c.在新节点中,删除不可能导出最优解的结点; //限界策略

d.将余下的新节点加入活动表(队列)中;

e.从活动表中选择结点再扩展; //分支策略

f.知道活动表为空

4、两种常见的活结点扩充方式(未看懂)

(1)先进先出队列(FIFO):从活结点表中取出结点的顺序与加入节点的顺序相同,因此活结点表的性质与队列相同;

(2)优先队列(耗费用小根堆,收益用大根堆),每个结点都有一个对应的耗费或受益。

-如果查找一个具有最小耗费的解,则活结点表可用小根堆来建立,下一个扩展结点就是具有最小耗费的活结点;

-如果希望搜索一个具有最大收益的解,则可用大根堆来构造活结点表,下一个扩展结点是具有最大收益的活结点。

示例1:

b300fb1ebcf4ba541ed9fbdba548782a.png

ef50f6adca7e409670fa3a25b509948a.png

通过判断重量加起来是否超过背包容量来判断是不是死节点

示例2:(未看懂)

4180b28058e1210ba4fcb944db34ceff.png

788c86ab1fdf8e271164020cc15e1cd4.png

二、8谜问题

1、问题定义

9ec84c5c33010dcb775914506bdc057d.png

2、代价函数

为经x到解的代价,x是当前结点;

(1)如果x是死结点或x的子树不含解,使

(2)如果x是活结点:

:从根到x的代价;
:由x产生解的代价估计;这里我们取:

9c095967b0b6896ad6fdf34ebcf73e1b.png

3、

4631454f1b9b3f32e750f84ead12f723.png

三、装载问题

1、问题定义

84206c0708b2eac4c084d1bb0951866e.png

8c24c8f85b72838adebeeca8714f59a7.png


2、解空间树

05e5ac19c80c8f5202592e70a687ab6f.png


3、FIFO队列分支限界

cd6841527ef0984168f1715d4c68443c.png
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,你的问题是关于分支限界实现装载问题的C++代码。 首先,需要明确最装载问题的定义:给定一些物品和一个容量为C的箱子,每个物品有各自的重量和价值,要求在不超过箱子容量的情况下,将价值最大化的物品装入箱子中。 接下来,我们可以使用分支限界来解决这个问题。具体思路如下: 1. 将物品按照单位重量的价值从大到小排序。 2. 定义一个节点,包含当前所选物品的重量、价值、剩余容量和已选择的物品。 3. 对于每个节点,计算其可行的子节点。如果子节点的重量小于箱子容量,则将子节点加入队列中。 4. 对于每个可行的子节点,计算其上界(即该节点之后能够获得的最大价值),并更新最解。 5. 选择上界最大的节点,将其扩展成子节点,重复步骤3-5,直到队列为空。 下面是实现装载问题的C++代码,其中使用了一个先队列来存储节点,并按照上界从大到小排序: ```c++ #include <iostream> #include <queue> #include <vector> #include <algorithm> using namespace std; struct Node { int weight; // 已选物品的总重量 int value; // 已选物品的总价值 int capacity; // 剩余容量 vector<int> items; // 已选择的物品编号 double upper_bound; // 上界 bool operator<(const Node& other) const { return upper_bound < other.upper_bound; } }; double get_upper_bound(const Node& node, const vector<int>& weights, const vector<int>& values, int n) { double ub = node.value; int j = node.items.size(); int total_weight = node.weight; while (j < n && total_weight + weights[j] <= node.capacity) { ub += values[j]; total_weight += weights[j]; j++; } if (j < n) { ub += (node.capacity - total_weight) * (double)values[j] / weights[j]; } return ub; } int best_value(const vector<int>& weights, const vector<int>& values, int capacity) { int n = weights.size(); vector<int> indices(n); for (int i = 0; i < n; i++) { indices[i] = i; } sort(indices.begin(), indices.end(), [&](int a, int b) { return (double)values[a] / weights[a] > (double)values[b] / weights[b]; }); priority_queue<Node> q; Node root{ 0, 0, capacity, {}, get_upper_bound({ 0, 0, capacity, {}, 0 }, weights, values, n) }; q.push(root); int best = 0; while (!q.empty()) { Node node = q.top(); q.pop(); if (node.upper_bound < best) { break; } if (node.value > best) { best = node.value; } int i = node.items.empty() ? 0 : node.items.back() + 1; if (i < n) { Node left = node; left.weight += weights[indices[i]]; left.value += values[indices[i]]; left.capacity -= weights[indices[i]]; left.items.push_back(indices[i]); left.upper_bound = get_upper_bound(left, weights, values, n); if (left.upper_bound >= best) { q.push(left); } Node right = node; right.items.push_back(indices[i]); right.upper_bound = get_upper_bound(right, weights, values, n); if (right.upper_bound >= best) { q.push(right); } } } return best; } int main() { vector<int> weights = { 2, 3, 4, 5 }; vector<int> values = { 3, 4, 5, 6 }; int capacity = 8; cout << best_value(weights, values, capacity) << endl; // 输出13 return 0; } ``` 希望能够对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值