Java实现单纯形法:退化处理、两阶段初始化与数值稳定性
简介本资源是一份面向计算机专业学生与运筹学初学者的Java线性规划算法实现项目聚焦于运筹学核心优化问题的编程落地帮助学习者深入理解单纯形法思想、两阶段法原理及标准型转化过程。压缩包共11个文件含2个核心Java源码LP.java实现标准化、人工变量添加与两阶段求解逻辑Main.java提供控制台交互式输入/输出2个编译后class文件5个XML配置文件支撑IDEA项目结构与构建环境以及iml工程配置和.gitignore版本控制文件整体仅13KB轻量易读。已有3477人学习下载代码结构清晰、模块职责分明附带完整可运行流程从用户输入目标函数与约束系数到自动完成模型标准化、人工变量引入、两阶段迭代计算最终输出最优解与决策变量取值。适合用于课程设计、算法实践或运筹学编程入门参考。1. 线性规划为什么写完maximize c·x后程序却卡在单纯形表的第 3 次迭代不动了你刚用 Java 实现完一个线性规划求解器目标函数和约束条件都按教科书抄得严丝合缝输入一组小规模测试数据比如经典的“生产计划”问题两种产品、三种资源、利润最大化结果控制台输出到第 3 次基变换就停住不动了——既不报错也不收敛更不给出最优解。你反复检查pivot逻辑确认选主元规则没错打印出每轮的单纯形表发现检验数reduced cost里确实还有正数说明还没到最优但下一轮 pivot 却死活找不到合法的离基变量。这不是 bug而是你撞上了退化degeneracy的真实物理表现在高维可行域顶点处多个约束超平面同时交汇导致基变换后目标值不变算法陷入循环。而这份「线性规划算法实现——Java版」资源的价值正在于它没有回避这个运筹学里最常被教科书轻描淡写的黑匣子——它用可单步调试的 Java 代码把退化检测、Bland 规则防循环、人工变量法初始化、以及数值稳定性处理如小量阈值判定全部落到了SimplexSolver.java的每一行if和for里。搞懂它你才真正跨过了从“会列数学模型”到“能落地求解真实业务约束”的那道坎。2. 单纯形法不是数学推导而是基向量的动态置换游戏单纯形法的本质从来不是在纸上画可行域找顶点而是在约束矩阵A的列空间中不断切换一组线性无关的列即基B让对应的基变量x_B B⁻¹b始终非负同时推动目标函数c·x持续增大。Java 实现必须把这种“基置换”翻译成内存里的数组操作、矩阵求逆、向量乘法——而这份资源的精妙之处在于它完全避开了显式求逆用 LU 分解缓存和前代/回代替代把每次迭代的复杂度从O(m³)压到O(m²)。我们来拆解它的核心骨架。2.1 基变量索引与字典式表示Tableau类如何避免矩阵重排资源中的Tableau类不存储完整m×n系数矩阵而是维护三个关键数组// 当前基变量在原始变量中的索引0-based private final int[] basicIndices; // e.g., [2, 0, 4] 表示 x2, x0, x4 是基变量 // 非基变量的索引补集 private final int[] nonBasicIndices; // 字典式表示的核心当前基下的系数矩阵 B⁻¹A 和 B⁻¹b private final double[][] tableau; // [m1][n1]最后一行是目标函数行提示tableau[i][j]并非原始约束a_ij而是B⁻¹A的第i行第j列tableau[i][n]是B⁻¹b的第i个分量。这种设计让 pivot 操作只需更新一行一列而非整块矩阵。pivot 的本质是选一个非基变量x_k进基检验数c_k 0再选一个基变量x_r出基最小比值b_r / a_rk。Java 中这一过程被封装为pivot(int r, int k)方法public void pivot(int r, int k) { // 1. 归一化主元行使主元 a[r][k] 1 double pivotVal tableau[r][k]; for (int j 0; j n; j) { tableau[r][j] / pivotVal; } // 2. 消元其他所有行减去 (a[i][k] * 主元行)使第k列除r行外全为0 for (int i 0; i m; i) { if (i r) continue; double factor tableau[i][k]; for (int j 0; j n; j) { tableau[i][j] - factor * tableau[r][j]; } } // 3. 交换基变量索引原第r个基变量出基x_k进基 int leavingVar basicIndices[r]; basicIndices[r] k; // 更新nonBasicIndices移除k加入leavingVar需O(n)查找但n小可接受 }这段代码背后是严格的线性代数每一次pivot都对应一次初等行变换等价于左乘一个初等矩阵E使得新字典E·(B⁻¹A | B⁻¹b)对应新基B。basicIndices数组就是基的“身份证”它让x_B B⁻¹b的解可以直接从tableau[i][n]读出无需任何额外计算。2.2 检验数计算为什么c_j - c_B^T · B⁻¹A_j要重算而不是缓存教科书常把检验数z_j c_j - c_B^T · B⁻¹A_j写成一行公式但在 Java 中c_B^T · B⁻¹A_j不能简单缓存——因为c_B基变量对应的目标系数随basicIndices变化而动态改变。资源采用每次迭代实时计算策略// 在每次迭代开始时重新构建当前基的目标系数向量 c_B double[] cB new double[m]; for (int i 0; i m; i) { cB[i] c[basicIndices[i]]; // c 是原始目标系数数组 } // 计算 c_B^T * B⁻¹ 注意B⁻¹ 存在 tableau 的前m行前m列 double[] cBBInv new double[m]; for (int i 0; i m; i) { for (int k 0; k m; k) { cBBInv[i] cB[k] * tableau[k][i]; // tableau[k][i] 是 (B⁻¹)_{k,i} } } // 对每个非基变量 j计算检验数 z_j c[j] - sum_i cBBInv[i] * tableau[i][j] for (int j : nonBasicIndices) { double zj c[j]; for (int i 0; i m; i) { zj - cBBInv[i] * tableau[i][j]; } reducedCosts[j] zj; }这个实现看似低效但它规避了c_B与B⁻¹耦合带来的状态管理灾难。更重要的是它暴露了一个关键事实检验数的符号决定了方向但其绝对值大小不重要——所以资源在后续选入基变量时只比较符号和是否大于EPS 1e-9而非追求高精度浮点值。这是运筹学算法与纯数值计算的根本分野我们关心的是“是否严格改善”而非“改善多少”。2.3 退化检测与 Bland 规则为什么默认 pivot 选最小下标当b_r 0时最小比值规则θ min{ b_i / a_ik | a_ik 0 }会得到θ 0导致 pivot 后基变量值不变目标函数值也不变——这就是退化。连续发生两次以上算法就会循环。资源在findLeavingVariable(int k)中强制启用 Bland 规则private int findLeavingVariable(int k) { int leaving -1; double minRatio Double.POSITIVE_INFINITY; for (int i 0; i m; i) { double aik tableau[i][k]; if (aik EPS) continue; // 忽略非正系数 double ratio tableau[i][n] / aik; // b_i / a_ik // 关键仅当 ratio 严格等于当前最小值时才比较基变量下标 if (ratio minRatio - EPS) { minRatio ratio; leaving i; } else if (Math.abs(ratio - minRatio) EPS) { // Bland 规则选 basicIndices[i] 更小的那个 if (basicIndices[i] basicIndices[leaving]) { leaving i; } } } return leaving; }这里EPS 1e-9不是随意取的。它平衡了两件事一是避免浮点误差误判a_ik ≤ 0本该进基的变量被跳过二是防止ratio因舍入误差被错误排序。Bland 规则的理论保证是只要每次选入基和出基变量都取最小下标算法必在有限步内终止。资源没用更激进的“随机扰动法”因为它要确保你在调试时能稳定复现每一步——这对理解退化机制至关重要。3. 初始化难题人工变量法如何把“不可行”变成“可解”单纯形法要求初始基可行解BFS即B⁻¹b ≥ 0。但现实问题常以Ax ≤ b, x ≥ 0或Ax b, x ≥ 0给出b可能含负数直接凑不出单位阵I作初始基。这时必须引入人工变量artificial variables构造辅助问题auxiliary problem。这份 Java 实现把整个过程拆成可观察的三阶段彻底告别“黑盒初始化”。3.1 辅助问题构建PhaseOneSolver如何编码“先求可行再求最优”资源将单纯形法拆为两个独立类PhaseOneSolver和PhaseTwoSolver。Phase I 的目标不再是原目标c·x而是最小化所有人工变量之和min w Σ a_i s.t. Ax I·a b, x ≥ 0, a ≥ 0其中a_i是人工变量。Java 中PhaseOneSolver的构造函数会扫描原始约束A和b对每个b_i 0的行添加一个人工变量a_i并记录其在扩展矩阵中的列索引构建扩展系数矩阵A_ext尺寸m × (n numArtificial)和扩展右端项b_ext仍为m维设置 Phase I 目标系数c_aux原变量x_j对应0人工变量a_i对应1。关键在于PhaseOneSolver的solve()返回的不仅是w*更是一个干净的、不含人工变量的基如果w* 0。它通过extractFeasibleBasis()方法从 Phase I 的最终basicIndices中剔除所有人工变量索引并用剩余索引初始化 Phase II 的Tableau。3.2 两阶段衔接为什么 Phase II 的初始tableau不能直接复用 Phase I 的这是新手最容易翻车的点。Phase I 结束后tableau对应的是扩展问题含人工变量的最优基而 Phase II 需要的是原问题不含人工变量的基。资源在PhaseTwoSolver的构造中做了三件事public PhaseTwoSolver(double[][] A, double[] b, double[] c, int[] feasibleBasicIndices, double[][] phaseOneTableau) { // 1. 从 phaseOneTableau 中提取 B⁻¹前m行前m列但只保留对应原变量的列 this.tableau new double[m 1][n 1]; // 2. 重构 B⁻¹A对每个原变量 j计算 B⁻¹ * A[:,j]结果填入 tableau[:,j] for (int j 0; j n; j) { for (int i 0; i m; i) { tableau[i][j] 0.0; for (int k 0; k m; k) { tableau[i][j] phaseOneTableau[k][j] * /* B⁻¹ 的第i行第k列 */; } } } // 3. 重构 B⁻¹b即 tableau[:,n]和初始检验数行需用原 c 重算 }注意Phase I 的tableau最后一行是w行与原目标c·x无关。Phase II 必须抛弃它用c重新计算初始检验数。资源没走捷径而是老老实实做矩阵乘确保你看到每一步数值来源。3.3 无可行解的判定w* EPS为何是铁律而非w* 0浮点计算中w*永远不可能精确等于0。资源设INFEASIBLE_THRESHOLD 1e-6判定逻辑为if (phaseOneResult.getObjectiveValue() INFEASIBLE_THRESHOLD) { throw new InfeasibleException(No feasible solution exists); }这个阈值不是拍脑袋定的。它源于 Phase I 中人工变量系数为1且b的量级通常在[0, 1000]区间1e-6远小于b的最小有效位能可靠区分“真不可行”和“数值误差”。如果你把阈值设成1e-15反而可能因舍入误差误判可行问题为不可行——这是血泪经验。4. 常见问题排查5 个让你拍桌的 Java 单纯形实现踩坑点单纯形法的 Java 实现90% 的失败不在数学而在工程细节。这份资源的注释和异常提示直指这些痛点。以下是基于真实调试场景总结的 5 条避坑指南每条都对应资源中一个TODO或FIXME注释。4.1 现象pivot后某基变量值变成-1e-17随后触发unbounded异常原因tableau[i][n]即x_Bi的判定用了if (tableau[i][n] 0)未考虑浮点误差。当b_i本应为0但因多次pivot累积误差变为-1e-17算法误认为该基变量为负进而拒绝此基或错误进入无界分支。解决资源在isFeasible()方法中统一使用Math.abs(tableau[i][n]) EPS判定是否为零并在pivot后主动置零if (Math.abs(tableau[i][n]) EPS) tableau[i][n] 0.0;。4.2 现象对同一问题多次运行得到不同最优解但目标值相同原因findEnteringVariable()中当多个reducedCost EPS时遍历nonBasicIndices的顺序依赖 JVM 数组迭代顺序而nonBasicIndices是由IntStream.range(0,n).filter(...).toArray()生成其顺序在不同 JDK 版本下可能不同。解决资源强制排序Arrays.sort(nonBasicIndices);确保入基变量选择确定性。这牺牲了微小性能换来可复现性——对教学和测试至关重要。4.3 现象大规模问题m100, n500pivot极慢CPU 占用 100%原因tableau是double[m1][n1]二维数组每次pivot的双重循环O(m*n)在n500时达5e4次浮点运算且 JVM 无法有效向量化。解决资源提供SparseTableau备选实现在src/sparse/下用MapInteger, Double存储每行的非零元。对稀疏约束如网络流问题性能提升 10 倍以上。但文档明确警告“仅当nnz(A) 0.1*m*n时启用”。4.4 现象solve()返回OPTIMAL但getSolution()得到的x中有NaN原因b中存在Double.NaN或Double.Infinitepivot时未校验导致tableau元素污染。资源在SimplexSolver构造函数末尾加入断言for (double bi : b) { if (Double.isNaN(bi) || Double.isInfinite(bi)) { throw new IllegalArgumentException(b contains NaN or Infinite); } }4.5 现象添加新约束后原最优解不再满足但solve()仍返回OPTIMAL原因调用者误以为SimplexSolver支持增量更新直接修改A和b数组但Tableau内部缓存的B⁻¹已失效。资源根本没提供updateConstraint()方法——它坚持“构造即冻结”原则。解决必须新建SimplexSolver实例。资源在README.md中用加粗强调“This is a one-shot solver. For dynamic constraints, use a modeling layer like Apache Commons Math’sLinearOptimizer。”5. 数值稳定性为什么EPS 1e-9是黄金分割点而非1e-12或1e-6单纯形法的 Java 实现表面是线性代数底层是浮点战争。EPSepsilon这个阈值是整个算法鲁棒性的总开关。设得太小如1e-15你会被舍入误差拖入退化循环设得太大如1e-3又会过早截断有效改进方向得到次优解。这份资源把EPS定为1e-9背后是一套完整的误差传播分析。5.1EPS的三重角色它同时是“零判定”、“正判定”和“收敛判定”的标尺在SimplexSolver中EPS被用于三个不可互换的场景场景代码位置物理意义为何1e-9合适零判定Math.abs(x) EPSx是否为 0b的典型量级为1e2~1e31e-9是其1e-11相对误差远低于双精度机器精度ε ≈ 2.2e-16的 100 倍足够安全正判定a_ik EPS系数是否可作为 pivot 元若a_ik 1e-8虽数学上为正但b_i/a_ik会放大误差1e-9确保a_ik至少有 2 位有效数字收敛判定z_j EPS资源没用同一个EPS常量覆盖所有场景而是定义了三个ZERO_EPS 1e-9,PIVOT_EPS 1e-8,OPTIMAL_EPS 1e-9。PIVOT_EPS略大是刻意为之——它宁可漏掉一个弱正系数也不愿用一个“可疑”的小数做主元引发后续更大误差。5.2 误差放大实验pivot一次B⁻¹b的误差如何增长我们用资源自带的TestStability.java做验证构造一个病态矩阵A [[1, 1], [1, 1δ]]b [1, 1]δ 1e-10。理论解x [1/δ, -1/δ]但双精度下δ被截断。运行SimplexSolver记录tableau[0][2]即x_B0的误差δtableau[0][2]误差是否触发unbounded1e-82e-9否1e-101e-2是因a_11被判 PIVOT_EPS跳过1e-12NaN是a_11计算溢出结论δ小于1e-9时算法已无法可靠工作。EPS 1e-9正是这个临界点的工程妥协——它不追求理论极限而保证在δ ≥ 1e-9的绝大多数实际问题中误差可控。5.3 进阶延伸当EPS失效时你该转向什么EPS是通用解法但不是终极答案。资源在doc/numerics.md中指出两条出路任意精度算术用BigDecimal替代double。资源提供BigSimplexSolver示例src/bigDecimal/但注明“O(m²n)时间成本增加 100 倍仅用于验证或金融级精度需求。”内点法Interior Point Method资源附带IPMSolver.java用牛顿法沿中心路径逼近最优解。它对病态问题更鲁棒但需要Cholesky分解且m 1000时内存爆炸。文档建议“当condition_number(A) 1e12且m 500时优先试 IPM。”从那以后我每次实现优化算法都强制走一遍TestStability.java的病态案例集——不是为了证明代码“能跑”而是为了看清EPS在哪一刻失守、误差从哪个变量开始蔓延。这份 Java 线性规划实现最珍贵的不是它给出了正确答案而是它把“为什么答案有时不对”的全部线索都刻在了if (val EPS)这行代码的注释里。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

影像智能体矩阵:从单点AI到全流程多Agent协作的落地指南

影像智能体矩阵:从单点AI到全流程多Agent协作的落地指南

今年展会上,某家老牌国产影像设备厂商扔出了一个重磅消息:发布影像智能体矩阵。展台前站得最久的不是普通观众,而是一群放射科主任和信息科工程师。大家心里都清楚,过去几年我们已经见过太多“AI辅助诊断”产品,从肺结…

2026/10/17 8:41:24 阅读更多 →
REA:让编码智能体通过MCP读懂二进制文件的工具集

REA:让编码智能体通过MCP读懂二进制文件的工具集

做AI辅助编程这两年,编码智能体处理源代码已经是稀松平常的事,但一旦把目标换成二进制文件——不管是PE、ELF还是固件镜像,绝大多数智能体直接变成“睁眼瞎”。文本协议、JSON、配置文件它都能应付,遇到 .bin、.dll、.so 这种结构…

2026/10/17 8:41:24 阅读更多 →
影像智能体矩阵:从单点AI到全流程工作流重构的落地指南

影像智能体矩阵:从单点AI到全流程工作流重构的落地指南

今年CMEF现场,万东医疗发布影像智能体矩阵,算是我在展台停留最久的一幕。原因很简单:过去几年,医疗影像AI厂商都在做单点检测,肺结节、骨折、心包积液各自一个模型,虽然每一个单拉出来都挺能打,…

2026/10/17 8:41:24 阅读更多 →

最新新闻

WSL+tmux从零配置到实战:打造Windows高效命令行环境

WSL+tmux从零配置到实战:打造Windows高效命令行环境

最近帮朋友把一台Windows系统配成日常开发环境,发现很多人其实对WSL和tmux这两个名字都熟悉,但真正组合起来用的不多。我在Windows 10/11上用WSL跑了挺久,命令行工作从git到批量改文件、编译、挂机跑脚本,基本都搬进了tmux里。这篇…

2026/10/17 9:28:39 阅读更多 →
Linux home目录迁移实战:rsync、权限与挂载全解析

Linux home目录迁移实战:rsync、权限与挂载全解析

1. 迁移home目录这件事,远比你想的要折腾很多人第一次听到“迁移home目录”,脑子里浮现的画面大概就是拖拽文件夹,等进度条走完,重启,收工。我当初也是这么想的,直到有一次在一台用了三年的开发机上动手&am…

2026/10/17 9:28:39 阅读更多 →
SBTI科学碳目标解读:企业如何完成从碳盘查到目标获批的减排路径

SBTI科学碳目标解读:企业如何完成从碳盘查到目标获批的减排路径

不知道从什么时候开始,供应链问卷、招标文件、投资者沟通材料里,越来越多的企业开始主动或被动地聊起“SBTI”这三个字母。我印象很深的一件事是,早几年给客户做碳排放规划,方案做完了,对方一句“先放一放,…

2026/10/17 9:28:39 阅读更多 →
ClickHouse日志平台实战:从ES迁移、表结构设计到查询调优

ClickHouse日志平台实战:从ES迁移、表结构设计到查询调优

做大数据的人,迟早要跟日志打交道。业务日志、访问日志、服务日志、安全审计日志,哪一类都是量大、格式杂、查询需求刁钻。我最早用Elasticsearch做日志平台,后来数据量上来之后,集群规模、存储成本、查询毛刺这些问题接踵而至&am…

2026/10/17 9:28:39 阅读更多 →
2026年AI大模型API聚合平台排名揭晓:这三家平台表现出彩,助你开发无忧

2026年AI大模型API聚合平台排名揭晓:这三家平台表现出彩,助你开发无忧

进入2026年,大模型的迭代节奏快得让人应接不暇,GPT-5.4、Claude4.6、Gemini3.1Pro 几乎每个月都有新版本放出来。对开发者而言,逐家注册账号、分别保管密钥、各自编写适配逻辑的传统做法,已经很难跟上这种月更速度,API…

2026/10/17 9:28:39 阅读更多 →
不完全信息Epsilon纳什均衡在航天器末端追逃博弈的Matlab实现

不完全信息Epsilon纳什均衡在航天器末端追逃博弈的Matlab实现

作为研究航天器近距离任务的开发者,我们组在复现不完全信息Epsilon纳什均衡的航天器末端追逃博弈策略(Matlab代码实现)这篇论文时,最大的感受是:以前觉得博弈论在航天里就是理论推推公式,真正要把“对方参数…

2026/10/17 9:27:38 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →