其他问题

一、搜索算法

1.1 深度优先搜索(DFS)

基本概念

深度优先搜索是一种沿着树的深度遍历节点的算法,尽可能深地搜索树的分支。

应用场景

  1. 图的连通分量
  2. 排列组合生成
  3. 棋盘类问题
  4. 回溯算法

例题1.1:八皇后问题

问题描述:在 \(8 \times 8\) 的棋盘上放置8个皇后,使得它们互不攻击(任意两个皇后不在同一行、同一列或同一对角线上)。

解题思路

  1. 使用DFS按行放置皇后
  2. 使用三个布尔数组标记列、主对角线、副对角线是否被占用
  3. 对角线编号技巧:主对角线 \(row-col+7\),副对角线 \(row+col\)
  4. 时间复杂度:\(O(n!)\),但通过剪枝可以大大减少搜索空间

例题1.2:数独求解

问题描述:解一个 \(9 \times 9\) 的数独,保证有唯一解。

解题思路

  1. 使用DFS回溯
  2. 每次选择可填数字最少的格子(剪枝优化)
  3. 使用位运算加速判断可填数字
  4. 时间复杂度:指数级,但实际运行很快

1.2 广度优先搜索(BFS)

基本概念

广度优先搜索是一种逐层遍历的算法,先访问离起点最近的节点。

应用场景

  1. 无权图的最短路径
  2. 状态空间搜索
  3. 连通分量
  4. 拓扑排序

例题1.3:迷宫最短路径

问题描述:给定一个 \(n \times m\) 的迷宫,'.'表示通路,'#'表示障碍,求从起点到终点的最短步数。

解题思路

  1. 使用BFS从起点开始扩展
  2. 使用队列存储待访问节点
  3. 使用距离数组记录每个位置到起点的距离
  4. 时间复杂度:\(O(nm)\)

例题1.4:八数码问题

问题描述:在 \(3 \times 3\) 的棋盘上,有8个方块和一个空格。每次可以将空格与相邻方块交换,求从初始状态到目标状态的最少步数。

解题思路

  1. 将状态编码为字符串或整数
  2. 使用BFS搜索状态空间
  3. 使用哈希表记录已访问状态
  4. 使用双向BFS优化
  5. 时间复杂度:状态数 \(9! = 362880\)

1.3 迭代加深搜索(IDDFS)

基本概念

结合DFS的空间效率和BFS的完备性,逐步增加深度限制进行DFS。

应用场景

  1. 状态空间大但解深度小的问题
  2. 不知道目标深度的情况

例题1.5:IDA*求解八数码

问题描述:使用迭代加深A*算法解决八数码问题。

解题思路

  1. 使用曼哈顿距离作为启发函数
  2. 逐步增加深度限制
  3. 使用估值函数剪枝:\(f(s) = g(s) + h(s)\)
  4. \(f(s) > depth\) 时剪枝

1.4 双向搜索

基本概念

从起点和终点同时开始搜索,在中间相遇。

应用场景

  1. 状态空间指数级增长的问题
  2. 知道起点和终点的搜索问题

例题1.6:15数码问题

问题描述\(4 \times 4\) 的棋盘上15个方块和一个空格,求从初始状态到目标状态的最少步数。

解题思路

  1. 状态空间巨大:\(16! \approx 2 \times 10^{13}\)
  2. 使用双向BFS
  3. 使用哈希表存储两个方向的已访问状态
  4. 遇到交集时得到答案

二、贪心算法

2.1 基本概念

贪心算法每一步都选择当前最优解,希望最终得到全局最优解。

适用条件

  1. 最优子结构
  2. 贪心选择性质

例题2.1:区间调度

问题描述:有 \(n\) 个活动,每个活动有开始时间 \(s_i\) 和结束时间 \(f_i\)。求最多能安排多少个互不冲突的活动。

解题思路

  1. 按结束时间从早到晚排序
  2. 选择结束时间最早且不与已选活动冲突的活动
  3. 时间复杂度:\(O(n \log n)\)

例题2.2:哈夫曼编码

问题描述:给定 \(n\) 个字符的出现频率,构建最优前缀编码,使编码总长度最小。

解题思路

  1. 使用最小堆维护频率最小的两个节点
  2. 每次取出两个最小节点,合并为新节点
  3. 新节点频率为两者之和,放回堆中
  4. 重复直到只剩一个节点
  5. 时间复杂度:\(O(n \log n)\)

例题2.3:加油站问题

问题描述:环形路线上有 \(n\) 个加油站,每个加油站有油量 \(gas[i]\),到下一站耗油 \(cost[i]\)。判断是否能绕行一圈,并求起点。

解题思路

  1. 如果总油量小于总耗油量,无解
  2. 从第一个加油站开始,累加剩余油量
  3. 如果剩余油量小于0,从下一站重新开始
  4. 时间复杂度:\(O(n)\)

三、分治算法

3.1 基本概念

将问题分解为若干子问题,递归求解,合并结果。

经典算法

  1. 归并排序
  2. 快速排序
  3. 最近点对
  4. 快速幂

例题3.1:归并排序求逆序对

问题描述:给定一个数组,求逆序对的数量。

解题思路

  1. 在归并排序过程中统计逆序对
  2. 合并两个有序数组时,如果左数组元素大于右数组元素,则左数组剩余元素都与该右数组元素构成逆序对
  3. 时间复杂度:\(O(n \log n)\)

例题3.2:快速选择

问题描述:在未排序数组中找到第 \(k\) 小的元素。

解题思路

  1. 类似快速排序,选择枢轴元素
  2. 将数组分为小于、等于、大于枢轴的三部分
  3. 根据 \(k\) 所在区间递归查找
  4. 期望时间复杂度:\(O(n)\)

例题3.3:平面最近点对

问题描述:给定平面上 \(n\) 个点,求距离最近的两个点。

解题思路

  1. \(x\) 坐标排序
  2. 分治:将点集分为左右两部分
  3. 递归求解左右两部分的最近点对
  4. 合并时检查跨分界线的点对
  5. 时间复杂度:\(O(n \log n)\)

四、二分与三分

4.1 二分查找

基本概念

在有序序列中查找满足条件的边界。

应用场景

  1. 有序数组查找
  2. 最大化最小值/最小化最大值
  3. 判定性问题

例题4.1:二分答案

问题描述:有 \(n\) 本书,每本书有 \(a_i\) 页。要抄写 \(m\) 本书,连续分配给 \(k\) 个人,每人抄写连续的书,求每人最多抄多少页。

解题思路

  1. 二分每人最多抄的页数 \(x\)
  2. 贪心判断:按顺序分配,使每人不超 \(x\)
  3. 如果能分配完,则 \(x\) 可行,否则不可行
  4. 时间复杂度:\(O(n \log \sum a_i)\)

例题4.2:旋转数组最小值

问题描述:一个递增数组旋转后,求最小值。

解题思路

  1. 二分查找,比较中间元素与右边界
  2. 如果中间元素小于右边界,最小值在左侧
  3. 如果中间元素大于右边界,最小值在右侧
  4. 如果相等,右边界左移
  5. 时间复杂度:\(O(\log n)\)

4.2 三分查找

基本概念

用于寻找单峰函数的极值。

应用场景

  1. 抛物线极值
  2. 单峰函数最值

例题4.3:函数最大值

问题描述:给定单峰函数 \(f(x)\),求在区间 \([l, r]\) 上的最大值。

解题思路

  1. 取三等分点 \(m1 = l + (r-l)/3\)\(m2 = r - (r-l)/3\)
  2. 比较 \(f(m1)\)\(f(m2)\)
  3. 如果 \(f(m1) < f(m2)\),极值在 \([m1, r]\),否则在 \([l, m2]\)
  4. 时间复杂度:\(O(\log (r-l))\)

五、前缀和与差分

5.1 前缀和

基本概念

\(pref[i] = \sum_{j=1}^{i} a[j]\)

应用场景

  1. 区间和查询
  2. 快速计算子矩阵和

例题5.1:子数组和为k

问题描述:给定一个整数数组和一个整数 \(k\),求有多少个子数组的和等于 \(k\)

解题思路

  1. 计算前缀和数组 \(pref\)
  2. 对于每个 \(i\),统计有多少 \(j < i\) 使得 \(pref[i] - pref[j] = k\)
  3. 使用哈希表存储前缀和出现次数
  4. 时间复杂度:\(O(n)\)

5.2 差分

基本概念

\(diff[i] = a[i] - a[i-1]\)

应用场景

  1. 区间加减操作
  2. 多次操作后查询

例题5.2:区间加法

问题描述:长度为 \(n\) 的数组,初始全为0。进行 \(m\) 次操作,每次给区间 \([l, r]\) 加上 \(k\)。求操作后的数组。

解题思路

  1. 使用差分数组
  2. 操作 \([l, r] + k\) 转化为 \(diff[l] += k\)\(diff[r+1] -= k\)
  3. 最后对差分数组求前缀和得到原数组
  4. 时间复杂度:\(O(n+m)\)

六、排序与选择

6.1 排序算法

常见算法

  1. 快速排序:平均 \(O(n \log n)\),最坏 \(O(n^2)\)
  2. 归并排序:稳定 \(O(n \log n)\)
  3. 堆排序:原地 \(O(n \log n)\)
  4. 计数排序:\(O(n+k)\),k为值域
  5. 基数排序:\(O(d(n+k))\)

例题6.1:第k大元素

问题描述:在未排序数组中找到第 \(k\) 大的元素。

解题思路

  1. 使用快速选择算法
  2. 使用堆:维护大小为 \(k\) 的最小堆
  3. 遍历数组,堆大小超过 \(k\) 时弹出最小元素
  4. 堆顶即为第 \(k\) 大元素
  5. 时间复杂度:\(O(n \log k)\)

例题6.2:合并区间

问题描述:给定多个区间,合并所有重叠的区间。

解题思路

  1. 按区间左端点排序
  2. 遍历区间,如果当前区间与结果最后一个区间重叠则合并
  3. 否则加入结果
  4. 时间复杂度:\(O(n \log n)\)

七、位运算与状压

7.1 位运算技巧

常用操作

  1. 判断奇偶:x & 1
  2. 取最低位的1:x & -x
  3. 去掉最低位的1:x & (x-1)
  4. 判断2的幂:x & (x-1) == 0

例题7.1:子集枚举

问题描述:枚举集合的所有子集。

解题思路

  1. 如果集合用二进制表示,子集枚举:
  2. 对于集合 \(mask\),子集 \(sub = mask\),每次 \(sub = (sub-1) & mask\)
  3. 直到 \(sub = 0\)
  4. 时间复杂度:\(O(2^n)\)

7.2 状态压缩DP

基本概念

用二进制位表示状态,常用于小规模集合问题。

例题7.2:旅行商问题

问题描述\(n\) 个城市,求从起点出发经过所有城市一次并回到起点的最短路径。

解题思路

  1. \(dp[mask][i]\) 表示已访问城市集合 \(mask\),当前在城市 \(i\) 的最短路径
  2. 状态转移:\(dp[mask][i] = \min(dp[mask \setminus \{i\}][j] + dist[j][i])\)
  3. 时间复杂度:\(O(n^2 \cdot 2^n)\)

八、构造与交互

8.1 构造题

特点

需要构造满足条件的解,通常有多种解法。

例题8.1:构造回文数组

问题描述:给定 \(n\),构造一个长度为 \(n\) 的数组,使得它是回文的,且所有元素互不相同,取值范围 \([1, 10^9]\)

解题思路

  1. 如果 \(n\) 为奇数,中间元素可以是任意值
  2. 从1开始递增填充两侧对称位置
  3. 如果 \(n > 2 \times 10^5\),需要特殊处理(但 \(n \leq 10^5\)

8.2 交互题

特点

程序与评测系统交互,需要根据反馈调整策略。

例题8.2:猜数字

问题描述:系统有一个 \([1, 10^9]\) 的整数,你可以询问一个数 \(x\),系统返回 \(x\) 与答案的关系(大于、小于、等于)。最多问50次。

解题思路

  1. 二分查找
  2. 每次询问中间值
  3. \(10^9 < 2^{30}\),所以30次足够
  4. 交互格式:输出询问,刷新缓冲区,读取回答

九、模拟与实现

9.1 模拟题

特点

按照题意直接模拟过程,考察代码实现能力。

例题9.1:表达式求值

问题描述:给定一个包含加减乘除和括号的表达式,求值。

解题思路

  1. 使用双栈:操作数栈和运算符栈
  2. 定义运算符优先级
  3. 中缀转后缀或直接计算
  4. 处理括号匹配

例题9.2:大整数运算

问题描述:实现大整数的加减乘除。

解题思路

  1. 用字符串或数组存储数字(逆序)
  2. 加法:按位相加,处理进位
  3. 乘法:模拟竖式计算
  4. 除法:模拟长除法

十、随机化算法

10.1 基本概念

利用随机性解决问题的算法。

例题10.1:随机快速排序

问题描述:实现随机化的快速排序。

解题思路

  1. 随机选择枢轴元素
  2. 避免最坏情况 \(O(n^2)\)
  3. 期望时间复杂度:\(O(n \log n)\)

例题10.2:蒙特卡洛方法

问题描述:用蒙特卡洛方法估算 \(\pi\)

解题思路

  1. 在正方形内随机撒点
  2. 统计落在内切圆内的点数
  3. \(\pi \approx 4 \times \frac{圆内点数}{总点数}\)

十一、近似算法与启发式

11.1 近似算法

在多项式时间内给出近似最优解的算法。

例题11.1:顶点覆盖近似算法

问题描述:给定无向图,求最小的顶点覆盖(近似解)。

解题思路

  1. 近似算法:每次选择一条边,将两个端点加入覆盖,删除所有关联边
  2. 近似比:2
  3. 时间复杂度:\(O(n+m)\)

11.2 启发式算法

基于经验或直观的算法,如遗传算法、模拟退火等。

例题11.2:模拟退火求解TSP

问题描述:用模拟退火求解旅行商问题的近似解。

解题思路

  1. 初始随机路径
  2. 定义邻域操作:交换两个城市
  3. 以一定概率接受劣解
  4. 温度逐渐降低

总结

学习建议

  1. 分类练习:按算法类型系统练习
  2. 理解本质:掌握每个算法的核心思想和适用场景
  3. 模板整理:总结常用算法的模板代码
  4. 综合应用:多做综合性题目,提高问题分析能力

常见考点

  1. 搜索算法的优化与剪枝
  2. 贪心算法的正确性证明
  3. 分治与递归的应用
  4. 二分与三分的灵活运用
  5. 构造题的思维训练
  6. 模拟题的代码实现能力

这些算法是OI竞赛的重要组成部分,需要大量的练习和思考。建议从基础题开始,逐步提高难度,掌握各类算法的应用场景和实现技巧。

posted @ 2026-01-13 16:28  Chestify  阅读(17)  评论(0)    收藏  举报