回溯法求解装载问题(DFS + 剪枝策略)
参考:https://blog.csdn.net/m0_38015368/article/details/80196634
问题描述:
有n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i的重量为wi,且
问是否有一个合理的装载方案,可将这n个集装箱装上这2艘轮船。如果有,找出一种装载方案。
问题分析:
如果一个给定装载问题有解,则采用下面的策略可得到最优装载方案。
(1)首先将第一艘轮船尽可能装满;
(2)将剩余的集装箱装上第二艘轮船。
将第一艘轮船尽可能装满等价于选取全体集装箱的一个子集,使该子集中集装箱重量之和最接近c1。由此可知,装载问题等价于以下特殊的0-1背包问题:
且
算法思路:
用子集树表示解空间,则解为n元向量{x1, ... ,xn }, xi∈{0, 1} 。
约束函数:
当前搜索的层i <= n时,当前扩展结点Z为子集树的内部结点,对于当前扩展结点,其右子树约束函数值与其父节点相同,则仅当满足cw+w[i] <= c时进入左子树,x[i]=1; 当cw+w[i] > c ,在以结点Z为根的子树中所有结点都不满足约束条件,因而该子树中解都是不可行解,因而将在该子树删去。
限界函数:
由于是最优化问题, 可利用最优解性质进一步剪去不含最优解的子树:
设Z是解空间树第i层上的当前扩展结点。
设 bestw: 当前最优载重量,
cw: 当前扩展结点Z的载重量 ;
r: 剩余集装箱的重量;
在以Z为根的子树中任意叶结点所相应的载重量不超过cw + r。因此,对于当前扩展结点,其左子树限界函数值与其父节点相同,则仅当cw + r ≤ bestw时,可将Z的右子树剪去。
即:cw + r > bestw 时搜索右子树,x[i]=0;
#include <iostream>
#include <cstring>using namespace std;int n; //集装箱数
int bw = 0; //best_weight:当前最优载重量(已搜索的解空间树中)
int cw = 0; //current_weight:当前载重量(从根结点到当前结点部分解)
int x[100]; //当前向量
int bestx[100]; //最优解向量
int w[100]; //weight:集装箱重量
int c1; //第一艘船最大载重量
int c2; //第二艘船最大载重量
int r; //rest:剩余集装箱重量void bacctrack(int i)
{//搜索到叶子结点,更新最优解 if(i > n){for(int i = 0; i < n; i++)bestx[i] = x[i];bw = cw;}r -= w[i];/*剪枝 + 搜索右儿子的约束函数值与其父节点相同; 左儿子的限界函数值与其父节点相同;所以在搜索左儿子时,则只需判断约束函数能否将其剪枝 搜索右儿子时,则只需判断限界函数能否将其剪枝 */ //搜索左儿子 if(cw + w[i] <= c1) {x[i] = 1;cw += w[i];bacctrack(i + 1);cw -= w[i]; //回溯到父节点时,cw要更新为: cw - w[i]}//搜索右儿子 if(cw + r > bw){x[i] = 0;bacctrack(i + 1); //回溯到父节点时,r要更新为:r + w[i] r += w[i]; }
} int main()
{cout << "请输入集装箱数量:" << endl; cin >> n;cout << "请输入两艘船最大载重量:" << endl;cin >> c1 >> c2; cout << "请输入集装箱重量:" << endl; for(int i = 1; i <= n; i++)cin >> w[i];//将r初始化为所有集装箱的重量之和,那么当前扩展结点的r = r - w[i],避免每次计算的前结点的cw + r for(int i = 1; i <= n; i++)r += w[i];bacctrack(1);//判断在第一艘船尽可能装满后,剩下的集装箱能否装入第二搜船 int rest_sum = 0; for(int i = 1; i <= n; i++){if(bestx[i] == 0){rest_sum += w[i];} }if(rest_sum > c2)cout << "无法装入" << endl;else{cout << "第一艘船装入的货物是:";for(int i = 1; i <= n; i++){if(bestx[i] == 1)cout << i << " ";}cout << endl;cout << "第二艘船装入的货物是:";for(int i = 1; i <= n; i++){if(bestx[i] == 0)cout << i << " ";}cout << endl;}return 0;
}
测试样例:
(1)
(2)
回溯法求解装载问题(DFS + 剪枝策略)相关推荐
- 回溯法 | 求解装载问题
问题描述: 有 n 个集装箱要装上一艘载重量为 W 的轮船,其中集装箱 i (1<=i<=n) 的重量,为wi.子啊装在体积不受限制的情况下,将尽可能重的集装箱装上轮船,当重量相同时要求选 ...
- 使用回溯法求解装载问题
回溯法解决装载问题(java实现) 问题描述:有n个集装箱要装上两艘载重量分别为C1和C2的轮船,其中集装箱i的重量为wi,且:∑ wi ≤ C1+C2. 求是否有一个合理的装载方案能将这 n 个集装 ...
- 回溯法 —— 求解0/1背包问题(剪枝)
0/1背包问题 题目描述: 有n个重量分别为w1,w2,-,wn的物品(物品编号为1~n),它们的价值分别为v1,v2,-,vn,给定一个容量为W的背包.设计从这些物品中选取一部分物品放入该背包的方案 ...
- 【算法分析】实验 4. 回溯法求解0-1背包等问题
目录 实验内容 实验目的 实验结果 步骤1:描述与分析 步骤2:策略以及数据结构 步骤3 步骤4 步骤5 步骤6 实验总结 实验内容 本实验要求基于算法设计与分析的一般过程(即待求解问题的描述.算法设 ...
- 算法设计与分析 实验三 回溯法求解地图填色问题
回溯法求解地图填色问题 一.实验目的与要求 1.实验基本要求: 2.实验亮点: 二.实验内容与方法 三.实验步骤与过程 1.未优化的回溯: (1)算法描述: (2)编程实现 (3)运行并测试: 2.对 ...
- java背包算法回溯法_【算法分析】实验 4. 回溯法求解0-1背包等问题
[TOC] 实验内容 本实验要求基于算法设计与分析的一般过程(即待求解问题的描述.算法设计.算法描述.算法正确性证明.算法分析.算法实现与测试),通过回溯法的在实际问题求解实践中,加深理解其基本原理和 ...
- 回溯法求解N皇后问题及其时间复杂度分析
回溯法求解N皇后问题及其时间复杂度分析 一.回溯法简介 1. 什么是回溯法? 2. 回溯法的时间复杂度分析 蒙特卡罗方法 蒙特卡罗方法在回溯法求解时间复杂度中的应用 二.回溯法求解N皇后问题 1. 回 ...
- 0027算法笔记——【回溯法】回溯法与装载问题
1.回溯法 (1)描述:回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法. (2)原 ...
- 回溯法求解0-1背包问题
回溯法求解0-1背包问题时比较随机序列和按 v/w 降序排列的算法 问题描述: 针对0-1背包问题,尝试用回溯法. 物品总数N=10,背包容量 C=26, 物品的重量数组为w={7,3,10,12,1 ...
最新文章
- SAP有用的NOTE(持续更新)
- 【LorMe云讲堂】梁玉婷:农田土壤微生物共存与功能识别调控
- eltable 无数据文案修改_有哪些适合十二月发的文艺文案?记录文案用这款图片便签...
- 裸奔、抽烟、凡尔赛,原来数学家玩得这么野……
- c++ 圆上任意点坐标计算_线性代数总结 第三章 向量代数与几何计算(空间平面和直线)...
- 运用范式的规范数据库设计的好处
- cuda nvidia安装程序失败_Ubuntu16.04安装nvidia-docker
- 中国男性最想娶回家的金庸女性角色排行榜zz
- 小技巧|Cadence安装之后,原理图DSN文件的默认图标不对如何进行修改
- 如何查看自己windows密钥
- python游戏数据分析
- java-redis java使用redisTemplate连接操作单台Redis
- python绘制等高线图
- excel编辑csv文件
- 使用tensorboard出现:“couldn‘t build proto file into descriptor pool!”的解决方法
- android开发百度地图步行导航
- AXURE手机版注册登录原型(下载+教学)
- 【观察】中国跨境电商出海再加速背后,如何破解行业同质化竞争困局?
- 三星账户联系人同步到手机上_如何将健身数据从Samsung Health同步到Google Fit
- Facebook推出Events应用 帮用户找到有趣活动