跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

算法基础:分治法核心思想与经典例题解析

分治法通过递归将大问题拆解为小问题求解。涵盖逆序对统计、第 k 小数查找、最大子段和及地毯填补四个经典案例。结合 C++ 代码详解归并排序变体、快速选择算法、区间扫描及二维分治策略,帮助理解分治核心逻辑与实现细节。

观心发布于 2026/2/22更新于 2026/10/2579 浏览
算法基础:分治法核心思想与经典例题解析

分治全称为分而治之,指把一个大问题转化为几个小的子问题,当所有子问题解决后,整个大问题也就迎刃而解。下面通过四个经典案例,带你深入理解分治策略在算法竞赛中的应用。

1. 逆序对统计

以洛谷 P1908 为例,求数组中的逆序对数量是分治最经典的应用之一。

思路分析 我们将原数组从中间位置一分为二。答案由三部分组成:左半部分的逆序对、右半部分的逆序对、以及跨越左右两部分的逆序对。递归处理左右两部分直到无法划分(只剩一个元素)。合并时,由于左右两边已分别有序,可以利用双指针高效计算跨越的逆序对数。若左指针指向的值大于右指针指向的值,则左指针及其后的所有元素均构成逆序对。

代码实现

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> v;
long long merge(int left, int right) {
    if (left >= right) return 0;
    int mid = (left + right) / 2;
    long long ret = 0;
    ret += merge(left, mid);
    ret += merge(mid + 1, right);
    
    // 归并前排序,方便统计跨越逆序对
    sort(v.begin() + left, v.begin() + mid + 1);
    sort(v.begin() + mid + 1, v.begin() + right + 1);
    
    int cur1 = left;
    int cur2 = mid + 1;
    while (cur1 <= mid && cur2 <= right) {
        if (v[cur1] <= v[cur2]) {
            cur1++;
        } else {
            ret += mid - cur1 + 1;
            cur2++;
        }
    }
    return ret;
}

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        int num;
        cin >> num;
        v.push_back(num);
    }
    cout << merge(0, v.size() - 1);
    return 0;
}

2. 求第 k 小的数

参考洛谷 P1923,利用快速排序的分区思想解决。

思路分析 定义区间 [left, right],选取基准值 key。通过三路划分将数组分为小于 key、等于 key、大于 key 三个区间。根据 k 所在的区间范围决定下一步递归方向:若 k 落在左侧,则在左边找;若落在中间,直接返回 key;若落在右侧,则在右边找第 k-c1-c2 小的数。

代码实现

#include <iostream>
#include <vector>
using namespace std;

vector<long long> v;
long long find_kth(int left, int right, int k) {
    int begin = left;
    int cur = begin + 1;
    int end = right;
    long long key = v[left];
    
    while (cur <= end) {
        if (v[cur] > key) {
            swap(v[cur], v[end]);
            end--;
        } else if (v[cur] < key) {
            swap(v[cur], v[begin]);
            begin++;
            cur++;
        } else {
            cur++;
        }
    }
    
    int c1 = begin - left;
    int c2 = end - begin + 1;
    
    if (k <= c1) return find_kth(left, begin - 1, k);
    else if (k <= c1 + c2) return key;
    else return find_kth(end + 1, right, k - c1 - c2);
}

int main() {
    int n, k;
    cin >> n >> k;
    k++; // 调整为 1-based 索引逻辑
    v.resize(n);
    for (int i = 0; i < n; i++) scanf("%lld", &v[i]);
    cout << find_kth(0, n - 1, k) << endl;
    return 0;
}

3. 最大子段和

对应洛谷 P1115,经典的 Divide and Conquer 应用。

思路分析 将序列 [l, r] 从中间 mid 切开,最大子段和必然出现在三种情况中:完全在左半边、完全在右半边、或者跨越中轴线。前两种情况递归求解,跨越中轴线的情况需要分别求出以 mid 为起点向左延伸的最大和,以及以 mid+1 为起点向右延伸的最大和,两者相加即为跨越最大值。

代码实现

#include <iostream>
using namespace std;
const int N = 2e5 + 10;
int n;
int a[N];

int dfs(int l, int r) {
    if (l == r) return a[l];
    int mid = (l + r) >> 1;
    int ret = max(dfs(l, mid), dfs(mid + 1, r));
    
    int suml = a[mid], sumr = a[mid + 1];
    int maxl = suml, maxr = sumr;
    
    for (int i = mid - 1; i >= l; i--) {
        suml += a[i];
        maxl = max(maxl, suml);
    }
    for (int i = mid + 2; i <= r; i++) {
        sumr += a[i];
        maxr = max(maxr, sumr);
    }
    return max(maxr + maxl, ret);
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    cout << dfs(1, n) << endl;
    return 0;
}

4. 地毯填补问题

对应洛谷 P1228,二维空间的分治策略。

思路分析 一维分治是将区间从中间切开,二维分治则将矩阵从中心切两刀,分成四个相等的小矩阵。假设公主在其中一个格子内,为了统一处理,我们在其余三个矩阵的中心交界处放置'假公主'(即铺设一块特殊地毯),使得四个子问题都包含一个目标点,从而可以递归继续分治。直到矩阵大小为 1x1 时停止。

代码实现

#include <iostream>
#include <vector>
using namespace std;

void dfs(int a, int b, int len, int x, int y) {
    if (len == 1) return;
    len /= 2;
    
    if (x < a + len && y < b + len) {
        cout << a + len << " " << b + len << " " << "1" << endl;
        dfs(a, b, len, x, y);
        dfs(a, b + len, len, a + len - 1, b + len);
        dfs(a + len, b, len, a + len, b + len - 1);
        dfs(a + len, b + len, len, a + len, b + len);
    } else if (x < a + len && y >= b + len) {
        cout << a + len << " " << b + len - 1 << " " << "2" << endl;
        dfs(a, b, len, a + len - 1, b + len - 1);
        dfs(a, b + len, len, x, y);
        dfs(a + len, b, len, a + len, b + len - 1);
        dfs(a + len, b + len, len, a + len, b + len);
    } else if (x >= a + len && y < b + len) {
        cout << a + len - 1 << " " << b + len << " " << "3" << endl;
        dfs(a, b, len, a + len - 1, b + len - 1);
        dfs(a, b + len, len, a + len - 1, b + len);
        dfs(a + len, b, len, x, y);
        dfs(a + len, b + len, len, a + len, b + len);
    } else {
        cout << a + len - 1 << " " << b + len - 1 << " " << "4" << endl;
        dfs(a, b, len, a + len - 1, b + len - 1);
        dfs(a, b + len, len, a + len - 1, b + len);
        dfs(a + len, b, len, a + len, b + len - 1);
        dfs(a + len, b + len, len, x, y);
    }
}

int main() {
    int k, x, y;
    cin >> k >> x >> y;
    int len = (1 << k);
    dfs(1, 1, len, x, y);
    return 0;
}

目录

  1. 1. 逆序对统计
  2. 2. 求第 k 小的数
  3. 3. 最大子段和
  4. 4. 地毯填补问题

更多推荐文章

查看全部
  • 学术写作中降低 AIGC 检测率的实用工具指南
  • wechat-need-web 浏览器扩展实现微信网页版访问
  • LLM 大模型:提升回答质量的关键在于提问技巧
  • Python 基础语法详解:变量、类型、运算符与输入输出
  • Spring Boot 4.0 虚拟线程时代:WebFlux 与 WebMVC 选型分析
  • C++ 算法入门:一维动态规划基础实战
  • 华为 OD 技术面试:C++ 核心考点与特性解析
  • 分布式训练框架的编程基础与 PyTorch RPC 实践
  • VS Code Copilot 实战指南:从安装到高级配置
  • LLM 微调实战:使用 Code-Llama 训练自定义代码数据集
  • 7 篇必读的大模型前沿论文精选
  • MATLAB 实现基于多目标粒子群算法(MOPSO)的无人机三维路径规划
  • OpenClaw 集成 QVeris 实现 AI 助手实时数据查询
  • IntelliJ IDEA 中配置使用 Claude Code 方法
  • 分裂二叉树的最大乘积
  • OpenClaw 赋能机器人,AI 代理实现具身智能与远程操控
  • AIGC 赋能现代教育:自动化课件与个性化学习实践
  • Vue 开源 AI 低代码表单设计器 FcDesigner 使用指南
  • Git 下载、安装与环境配置指南
  • TypeScript 核心概念与高频面试题详解

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online