【回溯算法】【Python实现】装载问题

2024-05-13 22:36

本文主要是介绍【回溯算法】【Python实现】装载问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • @[toc]
      • 问题描述
      • 问题转换
      • 回溯算法
      • `Python`实现
      • 时间复杂性

问题描述

  • 有一批共 n n n个集装箱要装上 2 2 2艘载重量分别为 c 1 c_{1} c1 c 2 c_{2} c2的轮船,其中集装箱 i i i的重量为 w i w_{i} wi,且 ∑ i = 1 n w i ≤ c 1 + c 2 \displaystyle\sum\limits_{i = 1}^{n}{w_{i}} \leq c_{1} + c_{2} i=1nwic1+c2
  • 是否有一个合理的装载方案可将这 n n n个集装箱装上这两艘轮船

问题转换

  • 先将第一艘轮船尽可能装满,然后将剩余的集装箱装上第二艘轮船
  • 装载问题等价于以下特殊的 0 − 1 0-1 01背包问题

{ max ⁡ ∑ i = 1 n w i x i s . t . ∑ i = 1 n w i x i ≤ c 1 x i ∈ { 0 , 1 } , 1 ≤ i ≤ n \begin{cases} \max\displaystyle\sum\limits_{i = 1}^{n}{w_{i} x_{i}} \\ s.t. \displaystyle\sum\limits_{i = 1}^{n}{w_{i} x_{i}} \leq c_{1} \end{cases} \kern{2em} x_{i} \in \set{0 , 1} , \kern{1em} 1 \leq i \leq n maxi=1nwixis.t.i=1nwixic1xi{0,1},1in


回溯算法

  • 用子集树表示解空间,根结点为第 0 0 0
  • 约束函数用于剪去不满足约束条件 ∑ i = 1 n w i x i ≤ c 1 \displaystyle\sum\limits_{i = 1}^{n}{w_{i} x_{i}} \leq c_{1} i=1nwixic1的子树
    • 在子集树的第 j j j层的结点 Z Z Z处,用 c w cw cw记为当前的装载重量,即 c w = ∑ i = 1 j w i x i cw = \displaystyle\sum\limits_{i = 1}^{j}{w_{i} x_{i}} cw=i=1jwixi
    • c w > c 1 cw > c_{1} cw>c1时,以结点 Z Z Z为根的子树中所有结点都不满足约束条件,因而该子树中的解均为不可行解,故可将该子树剪去
  • 限界函数用于剪去不含最优解的子树,从而改进算法在平均情况下的运行效率
    • Z Z Z是解空间树第 i i i层上的当前扩展结点, c w cw cw是当前载重量, b e s t w bestw bestw是当前最优载重量, r r r是剩余集装箱的重量,即 r = ∑ j = i + 1 n w j r = \displaystyle\sum\limits_{j = i + 1}^{n}{w_{j}} r=j=i+1nwj
    • 定义限界函数为 c w + r cw + r cw+r,在以 Z Z Z为根的子树中任一叶结点所相应的重量均不超过 c w + r cw + r cw+r,当 c w + r ≤ b e s t w cw + r \leq bestw cw+rbestw时,可将 Z Z Z的子树剪去
  • i = n i = n i=n时,算法搜索至叶结点,其相应的装载重量为 c w cw cw,如果 c w > b e s t w cw > bestw cw>bestw,则表示当前解优于当前最优解,此时更新 b e s t w bestw bestw
  • i < n i < n i<n时,当前扩展结点 Z Z Z是子集树中的内部结点
    • 该结点的左儿子表示 x [ i + 1 ] = 1 x[i + 1] = 1 x[i+1]=1的情形,仅当 c w + w [ i + 1 ] ≤ c 1 cw + w[i + 1] \leq c_{1} cw+w[i+1]c1时进入左子树,对左子树递归搜索
    • 该结点的右儿子表示 x [ i + 1 ] = 0 x[i + 1] = 0 x[i+1]=0的情形,由于可行结点的右儿子结点总是可行的,因此进入右子树时不需要检查约束函数,只需要检查限界函数

Python实现

def backtrack_loading(weights, capacity):n = len(weights)best_solution = []best_value = 0def constraint(weight):# 约束函数: 检查当前解是否满足容量限制return weight <= capacitydef bound(weight, index):# 限界函数: 计算当前解的重量总和加上剩余物品重量作为上界, 用于剪枝weight += sum(weight for weight in weights[index + 1:])return weightdef backtrack(solution, weight, value, index):nonlocal best_solution, best_valueif index == n:# 已经遍历完所有物品if value > best_value:# 如果当前解的重量更大, 更新最优解best_solution = solutionbest_value = valuereturn# 尝试选择当前物品weight += weights[index]if constraint(weight):# 如果满足约束函数, 继续探索下一个物品backtrack(solution + [weights[index]], weight, value + weights[index], index + 1)# 恢复回溯前状态weight -= weights[index]# 尝试不选择当前物品if bound(weight, index) > best_value:# 如果当前解的上界仍然可能更好, 继续探索下一个物品backtrack(solution, weight, value, index + 1)# 开始回溯搜索backtrack([], 0, 0, 0)return best_solution, best_valueweights = [2, 4, 5, 7]
capacity = 10best_solution, best_value = backtrack_loading(weights, capacity)print(f'最优解: {best_solution}')
print(f'最优值: {best_value}')
最优解: [2, 7]
最优值: 9

时间复杂性

  • 计算上界需要 O ( n ) O(n) O(n)时间,在最坏情况下有 O ( 2 n ) O(2^{n}) O(2n)个右儿子结点需要计算上界
  • 所以解装载问题的回溯算法所需的计算时间为 O ( n 2 n ) O(n 2^{n}) O(n2n)

这篇关于【回溯算法】【Python实现】装载问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/987022

相关文章

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Android实现在线预览office文档的示例详解

《Android实现在线预览office文档的示例详解》在移动端展示在线Office文档(如Word、Excel、PPT)是一项常见需求,这篇文章为大家重点介绍了两种方案的实现方法,希望对大家有一定的... 目录一、项目概述二、相关技术知识三、实现思路3.1 方案一:WebView + Office Onl

C# foreach 循环中获取索引的实现方式

《C#foreach循环中获取索引的实现方式》:本文主要介绍C#foreach循环中获取索引的实现方式,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、手动维护索引变量二、LINQ Select + 元组解构三、扩展方法封装索引四、使用 for 循环替代

Mysql如何解决死锁问题

《Mysql如何解决死锁问题》:本文主要介绍Mysql如何解决死锁问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录【一】mysql中锁分类和加锁情况【1】按锁的粒度分类全局锁表级锁行级锁【2】按锁的模式分类【二】加锁方式的影响因素【三】Mysql的死锁情况【1

Spring Security+JWT如何实现前后端分离权限控制

《SpringSecurity+JWT如何实现前后端分离权限控制》本篇将手把手教你用SpringSecurity+JWT搭建一套完整的登录认证与权限控制体系,具有很好的参考价值,希望对大家... 目录Spring Security+JWT实现前后端分离权限控制实战一、为什么要用 JWT?二、JWT 基本结构

一文带你搞懂Python中__init__.py到底是什么

《一文带你搞懂Python中__init__.py到底是什么》朋友们,今天我们来聊聊Python里一个低调却至关重要的文件——__init__.py,有些人可能听说过它是“包的标志”,也有人觉得它“没... 目录先搞懂 python 模块(module)Python 包(package)是啥?那么 __in

Java实现优雅日期处理的方案详解

《Java实现优雅日期处理的方案详解》在我们的日常工作中,需要经常处理各种格式,各种类似的的日期或者时间,下面我们就来看看如何使用java处理这样的日期问题吧,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言一、日期的坑1.1 日期格式化陷阱1.2 时区转换二、优雅方案的进阶之路2.1 线程安全重构2

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络

使用Python实现图像LBP特征提取的操作方法

《使用Python实现图像LBP特征提取的操作方法》LBP特征叫做局部二值模式,常用于纹理特征提取,并在纹理分类中具有较强的区分能力,本文给大家介绍了如何使用Python实现图像LBP特征提取的操作方... 目录一、LBP特征介绍二、LBP特征描述三、一些改进版本的LBP1.圆形LBP算子2.旋转不变的LB

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结