第6章 · 大事化小、小事化了——分治

按图解版第6章重建分治原理、与动态规划的区别、快速幂、Karatsuba、矩阵分块与Strassen、线性结构、树上通信与换根、地图路径分解。

学习目标

  • 能解释分治基本介绍与分治和动态规划的区别在“第6章 · 大事化小、小事化了——分治”中的适用条件
  • 能围绕“怎样证明分解后的子问题、合并步骤、递归终止与复杂度递推都成立?”运行正常与失败轨迹,定位第一处错误决策
  • 能用“第6章 · 大事化小、小事化了——分治的题面摘要、约束表、输入生成器、算法伪码或代码版本、复杂度推导、正确性理由、最小反例、实际输出与资源统计。”证明“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”

来源、目录与技术核对边界

“第6章 · 大事化小、小事化了——分治”以天瓏书店详细书目与目录核对段忠杰、顾业鸣著、中国水利水电出版社、ISBN 9787522615059、245 页以及全书 6 章;该页标出版日期 2023 年 6 月 1 日。河南省政府采购书目记录同一 ISBN、题名、作者和出版社,但出版时间写作 2023 年 5 月。日期口径相差一个月,本课程保留差异,不自行断言哪一天是正式首发日。

对“第6章 · 大事化小、小事化了——分治”而言,公开来源只提供书目和详细目录,不含可授权改写的完整正文;本站的解释、推导、代码、交互、练习和答案均为独立教学重写。目录页第 4 章和第 6 章标题存在明显 OCR 或排版异常,站内按上下文规范化标题,但在清单中披露校正。

“第6章 · 大事化小、小事化了——分治”的技术事实另以Strassen 1969 年快速矩阵乘法原始论文复核:技术来源 1。来源用于检查概念、语言语义或历史算法边界,不把现代竞赛规则静默投射成 2023 年原书的逐字内容。

围绕“怎样证明分解后的子问题、合并步骤、递归终止与复杂度递推都成立?”,先预测正确轨迹,再只注入“只计算递归子问题却遗漏跨分区贡献,使局部正确无法合成整体正确”。若不能用最小反例定位第一处错误决策,就拒绝当前算法解释。

从“递归调用两次就是分治吗”开始

先预测:Fibonacci递归把nn拆成n1n-1n2n-2,为什么不被视为高效分治?因为两个子问题高度重叠,递归树反复计算同一状态。分治的收益来自子问题规模缩小且大体独立,再用受控成本合并。

必须明确四件事:何时停止、怎样切分、子答案表示什么、怎样合并而不漏掉跨边界解。

6.1 分治基本介绍

6.1.1 原理

分治基本介绍的原理可写为递推:

T(n)=aT(n/b)+f(n)T(n)=aT(n/b)+f(n)

aa是子问题数,n/bn/b是子问题规模,f(n)f(n)是切分与合并成本。让总成本可见。

a=b=2a=b=2且每层合并总成本Θ(n)\Theta(n),树高log2n\log_2n

T(n)=2T(n/2)+Θ(n)=Θ(nlogn)T(n)=2T(n/2)+\Theta(n)=\Theta(n\log n)

Base case必须把规模真正降到可直接求解;若切分产生与原问题同样大的子问题,递归不会终止。

6.1.2 分治和动态规划的区别

分治和动态规划的区别不在“递归还是循环”,而在状态依赖:

  • 分治子问题通常由不相交输入区间产生,各算一次后combine;
  • 动态规划的不同路径频繁到达同一状态,需要memo或表格合并;
  • 二者都依赖最优子结构或可组合摘要,也可组合使用。

归并排序是分治;Fibonacci记忆化是DP;矩阵链DP又会在每个区间状态枚举分割点。算法名称不应替代依赖图分析。

6.2 数乘型分治

数乘型分治利用数字表示的结构减少重复乘法或大整数子乘法。

6.2.1 疯狂的细胞分裂

疯狂的细胞分裂可把“每代乘增长因子rr,共tt代”写为rtr^t。逐代乘需要t1t-1次;按指数奇偶递归:

rt={(rt/2)2,t evenr(rt/2)2,t oddr^t= \begin{cases} (r^{t/2})^2,&t\text{ even}\\ r(r^{\lfloor t/2\rfloor})^2,&t\text{ odd} \end{cases}
long long power(long long base, unsigned long long exponent) {
    long long result = 1;
    while (exponent > 0) {
        if (exponent & 1ULL) result *= base;
        exponent >>= 1ULL;
        if (exponent) base *= base;
    }
    return result;
}

整数会快速溢出;竞赛题常要求模幂,应把每次乘法用足够宽的中间类型后取模。矩阵快速幂把标量乘法替换为矩阵乘法,可计算线性递推。

6.2.2 简单的乘法

简单的乘法把大整数按baseBB拆成x=aB+b,y=cB+dx=aB+b,y=cB+d。直接展开需要四个半长乘法:

xy=acB2+(ad+bc)B+bdxy=acB^2+(ad+bc)B+bd

利用:

ad+bc=(a+b)(c+d)acbdad+bc=(a+b)(c+d)-ac-bd
BigInt karatsuba(BigInt x, BigInt y) {
    if (small(x) || small(y)) return x * y;
    auto [a, b] = split(x);
    auto [c, d] = split(y);
    BigInt z2 = karatsuba(a, c);
    BigInt z0 = karatsuba(b, d);
    BigInt z1 = karatsuba(a + b, c + d) - z2 - z0;
    return shift2(z2) + shift1(z1) + z0;
}

递推T(n)=3T(n/2)+O(n)T(n)=3T(n/2)+O(n),得到O(nlog23)O(n1.585)O(n^{\log_23})\approx O(n^{1.585})。小整数上额外分配与加减成本更大,应设置阈值回退普通乘法。

6.3 矩阵乘法的分治

6.3.1 神秘数字

矩阵乘法的分治先观察神秘数字“8”:把两个n×nn\times n矩阵各切成四块,结果每块是两个块乘积之和,总共需要8个n/2n/2规模矩阵乘法。

递推为:

T(n)=8T(n/2)+Θ(n2)=Θ(n3)T(n)=8T(n/2)+\Theta(n^2)=\Theta(n^3)

仅仅分块没有改变指数,但改善cache locality,并为减少递归乘法数提供代数入口。

6.3.2 Strassen快速矩阵乘法

Strassen快速矩阵乘法通过特定加减组合,只做7个半规模乘法,再重建四个结果块:

T(n)=7T(n/2)+Θ(n2)=Θ(nlog27)Θ(n2.807)T(n)=7T(n/2)+\Theta(n^2)=\Theta(n^{\log_27})\approx\Theta(n^{2.807})

的渐近优势不代表任意规模更快:padding、临时矩阵、cache、并行库和浮点误差都会提高交叉点。生产实现通常在大块上Strassen、小块回退高度优化的经典kernel。

6.4 线性结构问题的分治

线性结构问题的分治把数组按中点切开。完整答案有三类:全在左半、全在右半、跨越中点。Combine必须构造第三类,否则只取两个子答案会漏解。

6.4.1 自助餐厅(一)

自助餐厅(一)可先建立线性区间模型:每个位置有收益或等待代价,目标找总和最大的连续选择。左、右子问题给出各自最优区间;跨中点答案由左半最佳suffix加右半最佳prefix组成。

long long max_subarray(std::span<const long long> a) {
    if (a.size() == 1) return a[0];
    const std::size_t mid = a.size() / 2;
    long long left = max_subarray(a.first(mid));
    long long right = max_subarray(a.subspan(mid));
    long long suffix = best_suffix(a.first(mid));
    long long prefix = best_prefix(a.subspan(mid));
    return std::max({left, right, suffix + prefix});
}

每层combine线性扫描,总成本O(nlogn)O(n\log n)。它不是该问题最快算法,线性扫描DP可达O(n)O(n);价值在于学习“跨边界摘要”怎样使combine完备。

6.4.2 自助餐厅(二)

自助餐厅(二)进一步把摘要作为接口设计。一个区间若保存总和、最佳prefix、最佳suffix、最佳subarray,两个相邻区间可在O(1)O(1)合并:

sum=sumL+sumRprefix=max(prefixL,sumL+prefixR)suffix=max(suffixR,sumR+suffixL)best=max(bestL,bestR,suffixL+prefixR)\begin{aligned} sum&=sum_L+sum_R\\ prefix&=\max(prefix_L,sum_L+prefix_R)\\ suffix&=\max(suffix_R,sum_R+suffix_L)\\ best&=\max(best_L,best_R,suffix_L+prefix_R) \end{aligned}

这个monoid式摘要还能用于segment tree:静态分治变成支持区间查询和点更新的数据结构。

6.5 树形结构问题的分治

树天然由根和若干子树组成。树形结构问题的分治先postorder汇总子树,再preorder把根外信息传给孩子。

6.5.1 沟通成本

沟通成本设某节点为中心,目标为它到所有节点距离和。对一个固定root,DFS可同时求depth与subtree size,根答案为:

ans[root]=vVdepth[v]ans[root]=\sum_{v\in V}depth[v]

若对每个节点都重新DFS,成本O(n2)O(n^2)。相邻根之间的大部分距离变化具有统一规律,可以复用。

6.5.2 换根策略

换根策略把根从父节点uu移动到孩子vvvv子树内的size[v]size[v]个节点距离都减1,其余nsize[v]n-size[v]个节点距离都加1:

ans[v]=ans[u]+n2size[v]ans[v]=ans[u]+n-2\,size[v]
void reroot(int u, int parent) {
    for (int v : graph[u]) {
        if (v == parent) continue;
        answer[v] = answer[u] + node_count - 2 * subtree_size[v];
        reroot(v, u);
    }
}

一次postorder求size和初始答案,一次preorder传播所有答案,总成本O(n)O(n)。这是树上的divide/combine与信息复用结合。

6.6 再看路径规划——地图上的分治

再看路径规划——地图上的分治把大地图切成regions,在每个区域内部预计算边界portal之间的距离,查询时只在起点区域、终点区域和高层边界图上搜索。

正确combine要求任何跨区路径都经过已列出的边界接口;局部摘要必须保存足够的portal-to-portal成本。分区过小会使边界图巨大,分区过大又让局部搜索昂贵,层次化分割需要在预处理、内存与查询时间之间平衡。

正式节点与算法证据

  • :第 1 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 2 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 3 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 4 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 5 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 6 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 7 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 8 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 9 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 10 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 11 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 12 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 13 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 14 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。
  • :第 15 个正式节点要能回到“子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。”,并给出成功输入与失败反例。

约束到算法决策

先固定问题,再比较策略

怎样证明分解后的子问题、合并步骤、递归终止与复杂度递推都成立?

问题前提

写出分治基本介绍的输入域、输出合同、规模和数值范围。

算法决策

只比较能够完整覆盖分治和动态规划的区别前提的候选策略。

验收证据

保存第6章 · 大事化小、小事化了——分治的最小、边界与对抗输入。

正式节点:分治基本介绍、分治和动态规划的区别、数乘型分治、疯狂的细胞分裂、简单的乘法、矩阵乘法的分治、神秘数字、Strassen快速矩阵乘法、线性结构问题的分治、自助餐厅(一)、自助餐厅(二)、树形结构问题的分治、沟通成本、换根策略、再看路径规划——地图上的分治

执行轨迹

用同一输入比较正常与失败路径

  1. 01形式化分治基本介绍的输入与输出
  2. 02选择分治和动态规划的区别并声明不变量
  3. 03执行数乘型分治并记录成本
  4. 04用再看路径规划——地图上的分治核对正确性、终止和资源

必须保持:子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。

反例与证据包

让错误策略在最小输入上失败

当前基线满足:子问题覆盖原问题且边界不重不漏,合并恢复完整合同,基例保证终止。

小结

本章从分治基本介绍与原理出发,区分分治和动态规划;在数乘型分治中用疯狂的细胞分裂理解快速幂,用简单的乘法理解Karatsuba。矩阵乘法的神秘数字8引出Strassen快速矩阵乘法的7个递归乘积。

线性结构问题的分治通过自助餐厅(一)与(二)建立跨中点摘要;树形结构问题用沟通成本与换根策略把平方重复降为线性;地图上的分治则把局部路径与边界portal组合。参考文献应继续追踪算法的适用前提、数值稳定性和工程crossover,而不是只保留复杂度指数。

练习与答案

练习

  1. 问题 1:建立算法合同。 回答“怎样证明分解后的子问题、合并步骤、递归终止与复杂度递推都成立?”,并写出约束、决策、不变量和验收结果。
  1. 问题 2:构造最小反例。 只采用“只计算递归子问题却遗漏跨分区贡献,使局部正确无法合成整体正确”,怎样确认失败来自算法而不是实现噪声?
  1. 问题 3:覆盖正式节点。 用一个证据包串联分治基本介绍、分治和动态规划的区别、数乘型分治、疯狂的细胞分裂、简单的乘法、矩阵乘法的分治、神秘数字、Strassen快速矩阵乘法、线性结构问题的分治、自助餐厅(一)、自助餐厅(二)、树形结构问题的分治、沟通成本、换根策略、再看路径规划——地图上的分治,并解释为什么复杂度更低不必然在给定规模上更快。

名词解释

名词解释

本章出现的专业名词,用大白话再讲一遍。

分治基本介绍

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

分治和动态规划的区别

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

数乘型分治

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

疯狂的细胞分裂

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

简单的乘法

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

矩阵乘法的分治

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

神秘数字

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

Strassen快速矩阵乘法

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

线性结构问题的分治

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

自助餐厅(一)

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

自助餐厅(二)

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

树形结构问题的分治

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

沟通成本

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

换根策略

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

再看路径规划——地图上的分治

“第6章 · 大事化小、小事化了——分治”中的正式节点;需要同时说明前提、决策、正确性理由与成本边界。

资料与写作方式声明

本章以《深入浅出算法竞赛(图解版)》权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…