1. 项目概述:从“装东西”到“算最优”

三维装箱问题,听起来挺学术,但说白了,就是怎么把一堆大小、形状、重量各异的箱子,最有效率地塞进一个更大的容器里。这个“容器”可以是集装箱、卡车车厢、飞机货舱,甚至是仓库的一个角落。2024年五一数学建模联赛的E题,正是聚焦于这个在物流、仓储、制造等领域无处不在的经典优化难题。它绝不仅仅是“摆积木”那么简单,其核心挑战在于,如何在满足一系列复杂约束(如承重、稳定性、装载顺序、货物属性)的前提下,最大化空间利用率,或者最小化运输成本。

对于参加数学建模竞赛的同学们来说,这道题的价值在于,它完美地将理论算法与现实需求结合了起来。你不仅需要理解背包问题、启发式算法等经典模型,还得考虑实际物流场景中的“规矩”。比如,重的箱子能不能压轻的?易碎的货物必须放在哪里?先卸的货是不是应该后装?这些问题,让简单的几何填充变成了一个多维度的、动态的优化谜题。通过解决这个问题,你能深刻体会到,数学建模不是纸上谈兵,而是解决真实世界复杂决策的一把利器。无论你是编程新手,还是优化算法的爱好者,这道题都能带你从零开始,搭建一个完整的解决方案,体验从问题抽象、模型建立、算法实现到结果分析的完整闭环。

2. 核心思路拆解:化繁为简的建模哲学

面对三维装箱这样一个复杂问题,最忌讳的就是一上来就想写代码。一个好的开始是成功的一半,而建模的核心思路就是“分解”与“抽象”。我们需要把那个庞大的、令人望而生畏的原始问题,拆解成一系列可管理、可计算的子问题。

2.1 问题定义与约束条件梳理

首先,我们必须明确E题到底问了什么。通常,这类题目会提供一份货物清单,包含每件货物的长、宽、高、重量、类型(如普通、易碎、贵重)、以及可能的特殊要求(如必须朝向、不能倒置)。同时,也会给出容器的尺寸和承重上限。我们的目标函数很明确: 在满足所有约束的前提下,最大化容器空间利用率(即已装载货物总体积 / 容器容积) ,或者 最小化使用的容器数量

接下来是关键一步:梳理约束条件。这是模型是否“接地气”的分水岭。常见的硬性约束包括:

  1. 几何约束 :货物之间不能重叠,且必须完全置于容器内部。
  2. 承重约束 :容器底部或各层货物的累积重量不能超过限值。
  3. 稳定性约束 :货物必须被稳定支撑,通常要求其底面的大部分面积(如80%以上)得到下方货物或容器底部的支撑,防止在运输中倾倒。
  4. 朝向约束 :某些货物(如“此面向上”的箭头)有固定的放置方向,不能随意旋转。
  5. 分类约束 :易碎品不能放在重物下方;有毒有害物品需要隔离;贵重物品可能需要放在易于存取的位置。
  6. 装载顺序约束 :后卸的货先装(Last-In, First-Out, LIFO),这要求我们在三维空间中还要考虑“时间”维度,为货物安排一个合理的装载序列。

注意 :竞赛题目中,约束的表述可能隐含在描述里。务必逐字逐句分析,将每一条隐含的“业务规则”转化为明确的数学模型条件。漏掉一个约束,可能导致整个方案失效。

2.2 模型选择:精确解与启发式的权衡

明确了问题和约束,接下来要选择用什么样的数学模型和算法来求解。这里没有银弹,需要根据问题规模和复杂度进行权衡。

精确算法 ,如整数规划(IP)、混合整数线性规划(MILP),可以将问题形式化为一组数学方程,然后利用CPLEX、Gurobi等求解器寻找最优解。这种方法的好处是,只要给足时间,它能证明找到的解就是全局最优的(或者给出最优间隙)。对于小规模问题(如货物数量<50),这是一个非常有力的工具。在论文中,建立这样的模型能极大提升理论深度。

然而,三维装箱是NP-Hard问题。这意味着随着货物数量增加,求解精确解所需的时间会呈指数级爆炸。对于竞赛题目中动辄上百件货物的情况,精确算法可能在比赛时间内根本无法得到可行解。

因此, 启发式算法和元启发式算法 成为了更实际的选择。它们的核心思想是“用可接受的计算时间,去寻找一个高质量(但不一定最优)的可行解”。

  • 启发式算法 :基于直观或经验构造的规则。最经典的就是 墙式构建法 块构建法 。墙式法像砌墙一样,从容器的一个角落开始,优先放置大的、重的箱子,逐步向外扩展。块构建法则预先将一些能紧密贴合的小货物组合成规则的“块”,再将这些块视为整体进行放置,能有效减少碎片空间。
  • 元启发式算法 :提供了一种在高维解空间中“智能搜索”的框架。常用的包括:
    • 遗传算法(GA) :模拟生物进化,将装载方案编码为“染色体”,通过选择、交叉、变异操作迭代优化。
    • 模拟退火算法(SA) :模拟固体退火过程,以一定概率接受“更差”的解,从而有机会跳出局部最优陷阱。
    • 禁忌搜索(TS) :记录近期搜索历史(禁忌表),避免重复搜索,引导探索新区域。

在实际竞赛中,一个 分层混合策略 往往最有效:先用启发式规则(如按体积降序排列货物)快速生成一个较好的初始解,再使用元启发式算法(如模拟退火)对这个初始解进行微调和优化。同时,可以将精确算法用于解决子问题,比如用线性规划来确定某一层货物的最优平面布局。

3. 关键技术与实现细节

思路清晰后,我们需要把想法落地。这部分将深入几个关键技术点的实现细节,这些细节直接决定了算法的效率和效果。

3.1 空间表示与干涉检测

如何在计算机里表示容器内的剩余空间?这是第一个技术坎。最简单的是 三维网格法 ,将容器离散化为一个个小立方体格子。货物只能占据整数个格子。这种方法实现简单,干涉检测(判断是否重叠)只需要检查格子占用状态,但精度受网格大小影响,且内存消耗大。

更高效的方法是 角落空间法 。其核心思想是:容器内所有可用的放置位置,必然位于已放置货物所形成的“角落”里。我们维护一个“可用角落点”列表。每次放置一个新货物后,就在该货物新产生的上表面边缘和侧面,生成新的潜在角落点,并移除被占用的点。干涉检测则通过比较货物边界框与所有已放置货物边界框的位置关系来实现。

干涉检测的优化 至关重要。朴素的O(n²)两两比较在货物很多时会极慢。可以采用 空间划分法 加速,如:

  1. 三维网格索引 :即使不用网格法放置,也可以用较粗的网格来索引货物。只检查目标货物所在网格及相邻网格内的货物。
  2. 包围盒层次结构(BVH) :这是一项在计算机图形学中广泛使用的技术。将货物组织成一棵树状结构,快速排除明显不相交的物体组,大幅减少精确检测的次数。
# 一个简化的边界框干涉检测函数示例
def is_overlap(box1, box2):
    """判断两个轴对齐的立方体是否重叠
    box: (x_min, y_min, z_min, x_max, y_max, z_max)
    """
    # 如果在任一轴上分离,则不重叠
    if (box1[3] <= box2[0] or box2[3] <= box1[0]): # x轴
        return False
    if (box1[4] <= box2[1] or box2[4] <= box1[1]): # y轴
        return False
    if (box1[5] <= box2[2] or box2[5] <= box1[2]): # z轴
        return False
    return True # 在所有轴上都有重叠,则物体重叠

3.2 放置策略与评价函数

当有多个可放置的位置时,选择哪一个?这就需要 放置策略 评价函数 。评价函数用于量化某个放置位置的“好坏”。

常见的评价指标包括:

  • 重心最低 :优先选择使货物重心最低的位置,有助于整体稳定。
  • 空间紧凑性 :优先选择能让新货物与已有货物或容器壁贴得更紧的位置,减少产生零碎空间。
  • 角落填充 :优先填满角落,因为角落空间最难被后续货物利用。
  • 支撑面积最大化 :对于稳定性要求高的场景,优先选择支撑面积大的位置。

评价函数往往是这些指标的加权和。权重的设置需要根据具体问题调优,没有固定答案。一个典型的评价函数可能长这样: Score = w1 * (1 / 重心高度) + w2 * 接触面积 + w3 * (1 / 到角落的距离)

放置策略则决定了搜索这些位置并应用评价函数的顺序。例如:

  1. 最佳适应度下降(Best Fit Decreasing, BFD) :对所有货物按体积或重量降序排序。对每一件货物,枚举所有可能的放置位置和朝向,用评价函数打分,选择得分最高的位置放置。
  2. 首次适应度下降(First Fit Decreasing, FFD) :同样对货物排序,但选择第一个可放置的、且满足评价函数阈值的位置,速度更快但解的质量可能稍差。

3.3 稳定性与承重约束的实现

这是将学术模型与现实连接的关键环节。

稳定性约束 的实现,通常需要一个支撑度检查。假设货物A放在货物B(或容器底板)上,我们需要计算A的底面积有多少比例被B的上表面所支撑。这涉及到二维多边形相交面积的计算(将货物底面投影到XY平面)。如果支撑比例低于阈值(如80%),则认为放置不稳定。简化处理时,可以只考虑底面四个角点是否有支撑,但这不够精确。

承重约束 的实现更为复杂,因为它具有传递性。货物B不仅要承受自身重量,还要承受放在它上面的所有货物A的重量。这要求我们在放置货物时,动态维护一个“承重关系图”或递归计算累积重量。一种方法是采用 分层处理 :将容器在高度(Z轴)上划分为若干层,确保每一层货物的总重量不超过其下方层(或底板)的承重能力。这简化了计算,但可能损失一些灵活性。

实操心得 :在竞赛有限时间内,实现完美的物理模拟是不现实的。关键在于“合理简化”。例如,可以规定货物只能放置在容器底板或已放置货物的完整顶面上(即顶面必须水平且未被部分覆盖),这样就自动满足了支撑面积要求。承重约束可以简化为:任何货物正下方的支撑货物,其“剩余承重能力”必须大于待放货物的重量。这些简化能大幅降低实现难度,同时保证解的基本可行性。

4. 算法实现与编程实战

理论最终要靠代码实现。这里以Python为例,勾勒一个结合启发式与模拟退火算法的混合框架。选择Python是因为其丰富的科学计算库(如NumPy, SciPy)和相对友好的学习曲线,适合快速原型开发。

4.1 数据结构设计

良好的数据结构是高效算法的基础。我们需要定义几个核心类:

class Container:
    def __init__(self, length, width, height, max_weight):
        self.dim = (length, width, height)  # 尺寸
        self.max_weight = max_weight        # 最大承重
        self.placed_items = []              # 已放置的货物列表
        self.used_volume = 0.0
        self.current_weight = 0.0
        # 可用位置列表,每个位置是(x, y, z)坐标
        self.available_positions = [(0, 0, 0)] 

class Item:
    def __init__(self, id, length, width, height, weight, item_type):
        self.id = id
        self.dim = (length, width, height)  # 原始尺寸
        self.weight = weight
        self.type = item_type  # 如 'normal', 'fragile', 'heavy'
        self.rotation = 0      # 朝向编码,0-5代表6种可能旋转
        self.position = None   # 放置位置 (x, y, z),None表示未放置
        # 根据rotation计算当前朝向下的实际长宽高
        def get_current_dim(self):
            # 实现旋转逻辑,返回 (l, w, h)
            pass

4.2 启发式算法构建初始解

我们采用基于“角落空间”的墙式构建法来生成一个不错的起点。

def construct_wall_solution(container, items):
    """使用墙式构建法生成初始解"""
    # 1. 货物排序:按体积降序,其次按重量降序
    sorted_items = sorted(items, key=lambda x: (x.get_volume(), x.weight), reverse=True)
    
    for item in sorted_items:
        best_score = -float('inf')
        best_pos = None
        best_rot = 0
        
        # 2. 遍历所有可用角落位置
        for pos in container.available_positions:
            # 3. 遍历货物的所有可能旋转(通常6种)
            for rot in range(6):
                item.rotation = rot
                dim = item.get_current_dim()
                # 检查是否超出容器边界
                if not check_boundary(pos, dim, container.dim):
                    continue
                # 检查是否与已放置货物重叠
                if has_overlap(pos, dim, container.placed_items):
                    continue
                # 检查稳定性(简化版:检查底面四角是否有支撑)
                if not check_stability_simple(pos, dim, container):
                    continue
                # 检查承重(简化版:检查放置平面是否承重足够)
                if not check_weight_capacity(pos, dim, item.weight, container):
                    continue
                    
                # 4. 计算该放置位置的评价分数
                score = evaluate_position(pos, dim, item, container)
                if score > best_score:
                    best_score = score
                    best_pos = pos
                    best_rot = rot
                    
        # 5. 找到最佳位置,放置货物
        if best_pos is not None:
            place_item(container, item, best_pos, best_rot)
            update_available_positions(container) # 关键:更新可用角落点
        else:
            # 如果当前容器放不下,可以开启一个新容器(对于多容器问题)
            print(f"Item {item.id} cannot be placed in current container.")
            # ... 处理逻辑

update_available_positions 函数是核心。每当放置一个新货物后,我们需要在其顶部(Z+方向)和侧面(X+和Y+方向)的边缘生成新的潜在放置点,并过滤掉那些已经被占据或无效的点。

4.3 模拟退火优化

初始解虽然可行,但很可能不是最优的。我们可以用模拟退火算法来对其进行扰动和优化。

import math
import random

def simulated_annealing(container, initial_solution, initial_temp=1000, cooling_rate=0.995, iterations_per_temp=100):
    """模拟退火优化装载方案"""
    current_solution = initial_solution.copy() # 深拷贝当前解
    current_utilization = calculate_utilization(container, current_solution)
    best_solution = current_solution.copy()
    best_utilization = current_utilization
    
    temp = initial_temp
    
    while temp > 1e-3: # 终止温度
        for _ in range(iterations_per_temp):
            # 1. 产生邻域解:定义几种扰动操作
            new_solution = generate_neighbor(current_solution)
            
            # 2. 评估新解(需要快速增量计算,或重新运行简化放置)
            new_utilization = evaluate_solution(new_solution)
            
            # 3. 计算能量差 (我们最大化利用率,所以能量取负)
            delta_e = current_utilization - new_utilization # 注意这里是负能量差
            
            # 4. 接受准则
            if delta_e < 0 or random.random() < math.exp(-delta_e / temp):
                current_solution = new_solution
                current_utilization = new_utilization
                
                # 更新历史最优
                if current_utilization > best_utilization:
                    best_solution = current_solution.copy()
                    best_utilization = current_utilization
                    
        # 5. 降温
        temp *= cooling_rate
        
    return best_solution, best_utilization

def generate_neighbor(solution):
    """生成一个邻域解,常用操作有:"""
    op = random.choice(['swap', 'rotate', 'reinsert'])
    if op == 'swap':
        # 随机选择两个已放置的货物,尝试交换它们的位置(如果满足约束)
        i, j = random.sample(range(len(solution)), 2)
        new_solution = solution.copy()
        new_solution[i], new_solution[j] = new_solution[j], new_solution[i]
        # 注意:交换后可能需要局部调整以满足约束,这是一个复杂操作
    elif op == 'rotate':
        # 随机选择一个货物,改变其朝向
        idx = random.randint(0, len(solution)-1)
        new_solution = solution.copy()
        new_solution[idx].rotation = random.randint(0, 5)
    elif op == 'reinsert':
        # 随机移除一个货物,然后尝试用放置策略重新插入
        idx = random.randint(0, len(solution)-1)
        removed_item = solution.pop(idx)
        # 将removed_item重新用启发式规则放入(可能放回不同位置)
        new_solution = try_reinsert(solution, removed_item)
    return new_solution

注意事项 :模拟退火中的 generate_neighbor evaluate_solution 函数设计是难点。直接交换两个货物的位置很可能导致重叠,因此需要一个“修复”步骤,或者设计更智能的扰动方式,比如只对当前利用率低的局部区域进行重排。此外,重新评估整个方案的利用率可能很耗时,需要考虑增量计算或使用代理模型。

5. 结果可视化与方案评估

一个优秀的数学建模论文,不仅要有好的模型和算法,还要有清晰的结果展示。对于三维装箱问题,可视化是无可替代的。

5.1 利用Matplotlib进行3D可视化

Python的Matplotlib库虽然主要用于2D,但其mplot3d工具包可以绘制基本的三维立方体,非常适合展示装载方案。

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection

def visualize_packing(container, items):
    fig = plt.figure(figsize=(12, 10))
    ax = fig.add_subplot(111, projection='3d')
    
    # 绘制容器边框
    l, w, h = container.dim
    ax.set_xlim([0, l])
    ax.set_ylim([0, w])
    ax.set_zlim([0, h])
    ax.set_xlabel('Length')
    ax.set_ylabel('Width')
    ax.set_zlabel('Height')
    
    # 为不同类型货物定义颜色
    color_map = {'normal': 'blue', 'fragile': 'red', 'heavy': 'green'}
    
    # 绘制每个货物
    for item in items:
        if item.position is None:
            continue
        x, y, z = item.position
        l_i, w_i, h_i = item.get_current_dim()
        
        # 定义立方体的八个顶点
        vertices = [
            [x, y, z],
            [x+l_i, y, z],
            [x+l_i, y+w_i, z],
            [x, y+w_i, z],
            [x, y, z+h_i],
            [x+l_i, y, z+h_i],
            [x+l_i, y+w_i, z+h_i],
            [x, y+w_i, z+h_i]
        ]
        
        # 定义六个面
        faces = [
            [vertices[0], vertices[1], vertices[5], vertices[4]], # 前面
            [vertices[1], vertices[2], vertices[6], vertices[5]], # 右面
            [vertices[2], vertices[3], vertices[7], vertices[6]], # 后面
            [vertices[3], vertices[0], vertices[4], vertices[7]], # 左面
            [vertices[4], vertices[5], vertices[6], vertices[7]], # 顶面
            [vertices[0], vertices[1], vertices[2], vertices[3]]  # 底面
        ]
        
        # 创建面集合并添加
        face_collection = Poly3DCollection(faces, alpha=0.8, linewidths=0.5, edgecolors='k')
        face_collection.set_facecolor(color_map.get(item.type, 'gray'))
        ax.add_collection3d(face_collection)
        
        # 可选:在货物中心添加ID标签
        ax.text(x+l_i/2, y+w_i/2, z+h_i/2, str(item.id), color='white', ha='center', va='center', fontsize=8)
    
    plt.title('3D Packing Visualization')
    # 调整视角以便观察内部
    ax.view_init(elev=20, azim=45)
    plt.show()

这张图能一目了然地展示货物摆放是否紧凑、是否有大块空间浪费、不同类型货物的分布等。在论文中插入这样的可视化图表,能极大提升表现力。

5.2 量化指标分析与方案对比

除了“看上去”很满,我们还需要用数据说话。关键的量化指标包括:

  • 空间利用率 :已装载货物总体积 / 容器容积。这是最核心的指标。
  • 重量利用率 :已装载货物总重量 / 容器最大承重。对于重货运输,这个指标可能比空间更重要。
  • 重心位置 :计算整个装载方案的重心坐标(X_cg, Y_cg, Z_cg)。理想情况下,重心应尽可能低且靠近容器中心,以保证运输稳定性。
  • 支撑达标率 :统计满足支撑面积约束的货物比例。
  • 约束违反情况 :记录有多少货物违反了朝向、分类隔离等约束。

为了证明你算法的优越性,需要设计对比实验。常见的对比基线包括:

  1. 简单规则 :如按货物编号顺序放置(First Fit),或仅按体积降序放置(BFD without evaluation)。
  2. 经典算法 :实现文献中经典的墙式算法或块构建算法。
  3. 商业软件结果 (如果可能):与一些开源或演示版的装箱工具结果进行对比。

将你的混合算法(启发式+模拟退火)与这些基线方法在相同数据集上运行,用上述指标制作对比表格。

算法 空间利用率 重量利用率 重心高度 计算时间(秒) 约束违反数
顺序放置(FF) 68.5% 72.3% 1.8m 0.5 2
墙式构建(BFD) 82.1% 85.6% 1.5m 2.1 0
本文混合算法 89.7% 91.2% 1.3m 15.7 0

通过这样的表格,可以清晰展示你的算法在核心指标上的提升,同时坦诚地指出其代价(如更长的计算时间)。在论文中,还需要对结果进行统计分析,比如计算提升的百分比,并使用箱线图展示算法在多组随机数据上的稳定性。

6. 参赛实战技巧与避坑指南

结合数学建模竞赛的特点,分享一些书本上不会写的实战经验。

6.1 论文写作的核心要点

数学建模竞赛,“模型”和“建模”各占一半。一个优秀的解决方案必须通过论文清晰传达。论文结构通常包括:摘要、问题重述、模型假设、符号说明、模型建立与求解、结果分析、模型评价与推广、参考文献、附录。

摘要 是重中之重,它决定了评委的第一印象。必须用300-500字浓缩整个工作的精华,必须包含:针对什么问题、建立了什么模型、采用了什么算法、得到了什么结果(关键数据)、有何优势与特色。避免空洞的形容词,多用数据说话,例如“本文提出的混合启发式算法,将空间利用率从基准算法的82%提升至89.7%”。

模型假设 要合理且必要。例如,“假设所有货物均为刚体,装卸过程中不变形”、“忽略货物之间的摩擦力”。好的假设能简化问题,但要说明其合理性。

模型建立部分 是展示你数学功底的地方。不要只扔出一堆公式,要用文字描述每个公式的物理或逻辑意义。将复杂的模型分解为子模型(如几何约束子模型、稳定性子模型)来阐述,会更清晰。

结果分析部分 ,图表比文字更有说服力。除了前面提到的3D可视化图和对比表格,还可以绘制:

  • 利用率迭代曲线图 :展示模拟退火过程中,解的质量如何随着迭代逐步提升。
  • 重心分布散点图 :展示不同算法得到的装载方案其重心在XY平面上的投影,验证是否集中。
  • 时间-效果对比图 :展示不同规模问题下,各算法的计算时间和利用率关系。

6.2 代码实现与调试的坑

  • 浮点数精度问题 :在判断是否重叠、是否支撑时,直接使用 == < > 比较浮点数非常危险。要使用一个很小的容差 epsilon (如1e-6)。 if abs(a - b) < epsilon: 来判断相等, if a < b - epsilon: 来判断小于。
  • 算法效率瓶颈 :初期原型跑一个小数据集很快,但数据量一大就卡死。90%的时间可能花在了全量的干涉检测上。 务必尽早引入空间索引(如三维网格或BVH)进行加速 。在代码中关键函数旁用 @profile 装饰器(需安装 line_profiler )进行性能剖析,找到热点。
  • 约束冲突与修复 :在模拟退火的扰动操作后,新解可能违反约束。有两种策略:1) 设计“保约束”的扰动算子,难度大;2) 在评价函数中为违反约束的行为施加巨大的惩罚项(罚函数法),引导算法远离不可行解。后者实现更简单,但惩罚权重的设置需要调参。
  • 随机性管理 :启发式和元启发式算法通常包含随机因素。为了结果可复现, 务必固定随机数种子 (如 random.seed(42) np.random.seed(42) )。在论文中应报告多次运行(如10次)的平均结果和标准差,以证明算法的稳定性。

6.3 时间管理与团队协作

三天或四天的比赛,时间极其紧张。一个粗略的时间分配建议:

  • 第一天上午 :全体成员深入讨论题目,厘清所有已知条件和隐含约束,达成对问题的一致理解。确定初步的建模方向和分工(建模、编程、写作)。
  • 第一天下午至第二天全天 :建模和编程主力搭建模型框架和算法原型,用最简单的数据测试通路。写作同学可以开始撰写问题重述、模型假设和符号说明。
  • 第三天 :算法优化、调试、跑出主要结果。写作同学同步撰写模型建立、求解部分,并制作图表。
  • 第四天(或最后一天) :集中进行结果分析、模型评价,完成摘要、结论,并进行全文的整合、润色、排版和最终检查。 最后半天一定要留出来做全文检查和格式调整

团队协作的关键是 频繁沟通 版本管理 。每天至少开两次短会同步进度。代码和论文使用Git进行版本控制,避免文件覆盖或丢失。论文写作推荐使用LaTeX,虽然学习曲线稍陡,但能产出极其专业、美观的排版,避免Word在最后时刻格式崩坏的悲剧。

这道三维装箱题目,就像一场微型的系统工程实践。它考验的不仅仅是数学和编程能力,更是将模糊的现实需求转化为清晰模型的能力、在复杂约束中寻找平衡点的决策能力、以及将技术工作有效呈现的沟通能力。当你看到自己编写的算法将一堆杂乱的数据,规整地填入虚拟容器,并计算出漂亮的利用率数字时,那种成就感,正是数学建模最吸引人的地方。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐