【回溯】n皇后问题Python实现

### 文章目录

  • [@[toc]](#文章目录 @[toc] 问题描述 问题转换 回溯法 时间复杂性 Python实现)
  • [问题描述](#文章目录 @[toc] 问题描述 问题转换 回溯法 时间复杂性 Python实现)
  • [问题转换](#文章目录 @[toc] 问题描述 问题转换 回溯法 时间复杂性 Python实现)
  • [回溯法](#文章目录 @[toc] 问题描述 问题转换 回溯法 时间复杂性 Python实现)
  • [时间复杂性](#文章目录 @[toc] 问题描述 问题转换 回溯法 时间复杂性 Python实现)
  • [`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=1∑nwi≤c1+c2
  • 是否有一个合理的装载方案可将这 n n n个集装箱装上这两艘轮船

问题转换

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

{ 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} , 1 \leq i \leq n ⎩ ⎨ ⎧maxi=1∑nwixis.t.i=1∑nwixi≤c1xi∈{0,1},1≤i≤n


回溯法

  • 用子集树表示解空间,根节点为第 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=1∑nwixi≤c1的子树
    • 在子集树的第 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=1∑jwixi
    • 当 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+1∑nwj
    • 定义限界函数为 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+r≤bestw时,可将 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的情形,由于可行结点的右儿子结点总是可行的,因此进入右子树时不需要检查约束函数,只需要检查限界函数

时间复杂性

  • 在每个结点处算法花费 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实现

python 复制代码
def backtrack_loading(weights, capacity):
    n = len(weights)
    best_solution = []
    best_value = 0

    def constraint(solution):
        # 约束函数: 检查当前解是否满足容量限制
        total_weight = sum(item for item in solution)

        return total_weight <= capacity

    def bound(solution, index):
        # 限界函数: 计算当前解的重量总和加上剩余物品重量作为上界, 用于剪枝
        total_weight = sum(item for item in solution) + sum(weight for weight in weights[index + 1:])

        return total_weight

    def backtrack(solution, value, index):
        nonlocal best_solution, best_value

        if index == n:
            # 已经遍历完所有物品
            if value > best_value:
                # 如果当前解的重量更大, 更新最优解
                best_solution = solution
                best_value = value

            return

        # 尝试选择当前物品
        weight = weights[index]

        if constraint(solution + [weight]) and bound(solution + [weight], index) >= best_value:
            # 如果满足约束函数, 继续探索下一个物品
            backtrack(solution + [weight], value + weight, index + 1)

        # 尝试不选择当前物品
        if bound(solution, index) >= best_value:
            # 如果当前解的上界仍然可能更好, 继续探索下一个物品
            backtrack(solution, value, index + 1)

    # 开始回溯搜索
    backtrack([], 0, 0)

    return best_solution, best_value


weights = [2, 4, 5, 7]
capacity = 10

best_solution, best_value = backtrack_loading(weights, capacity)

print(f'最优解: {best_solution}')
print(f'最优值: {best_value}')
shell 复制代码
最优解: [2, 7]
最优值: 9

相关推荐
阡之尘埃2 小时前
Python数据分析案例61——信贷风控评分卡模型(A卡)(scorecardpy 全面解析)
人工智能·python·机器学习·数据分析·智能风控·信贷风控
丕羽5 小时前
【Pytorch】基本语法
人工智能·pytorch·python
bryant_meng5 小时前
【python】Distribution
开发语言·python·分布函数·常用分布
m0_594526306 小时前
Python批量合并多个PDF
java·python·pdf
工业互联网专业6 小时前
Python毕业设计选题:基于Hadoop的租房数据分析系统的设计与实现
vue.js·hadoop·python·flask·毕业设计·源码·课程设计
钱钱钱端7 小时前
【压力测试】如何确定系统最大并发用户数?
自动化测试·软件测试·python·职场和发展·压力测试·postman
慕卿扬7 小时前
基于python的机器学习(二)—— 使用Scikit-learn库
笔记·python·学习·机器学习·scikit-learn
Json____7 小时前
python的安装环境Miniconda(Conda 命令管理依赖配置)
开发语言·python·conda·miniconda
小袁在上班7 小时前
Python 单元测试中的 Mocking 与 Stubbing:提高测试效率的关键技术
python·单元测试·log4j
白狐欧莱雅7 小时前
使用python中的pygame简单实现飞机大战游戏
经验分享·python·游戏·pygame