Classic Algorithms

本篇笔记概述了经典算法的多种类型,包括倒排索引、回溯算法、分治法、动态规划、贪心算法、近似算法、局部搜索、随机化算法、并行算法以及外部排序。每种算法都配有具体的例子和复杂度分析,帮助读者理解其应用场景和实现方式。通过这些内容,读者可以掌握算法设计的基本思想和技巧,为解决实际问题提供理论基础和实践指导。(由 gpt-4o-mini 生成摘要)

1. 倒排索引 Inverted File Index

1.1. Optimize a Search Engine

读取时的处理:

  • word stemming
  • stop words

阈值(thresholding)

  • document: 只检索前面 xx 个按权重排序的文档
  • query:把带查询的 terms 按照出现的频率升序排序

搜索引擎的相关性度量(relevance measurement)

  • 准确率(precision):指检索出相关文档数与检索出的文档总数的比率,衡量的是检索系统的查准率 PR=RR/(RR+IR)P_R=R_R/(R_R+I_R)
  • 召回率(recall):指检索出的相关文档数和文档库中所有的相关文档数的比率,衡量的是检索系统的查全率 RR=RR/(RR+RN)R_R=R_R/(R_R+R_N)

6dDuxn44.png

2. 回溯 Backtracing

  • 解空间约束

求解问题的一个可靠方法是找出所有可能得情况,逐一检查,找到正确答案。回溯(backtracing) 算法利用了剪枝(pruning) ,可以减少对大量已知不可能的情况的显示检查。

  • 尽量选择从少到多的搜索方式,这样在剪枝的时候可以一次性剪掉更多的情况数。

2.1. Minimax Search & α-β Pruning

定义 goodness 函数为 f(P)=WComputerWHumanf(P) = W_\text{Computer} - W_\text{Human},则 Human 想要最小化 f(P)f(P) 而 Computer 想要最大化 f(P)f(P)

αβ\alpha-\beta 剪枝的核心思想:根据当前局面可以推定不会影响上层节点结果的就可以进行剪枝。

习题

Given the following game tree, which node in the right subtree is the first node to be pruned with α-β pruning algorithm?

答案

D。可以分析而知:无论节点 dd 的值是多少,都不会影响到根节点 6868 的值,故可以进行剪枝。

另外左子树中可以减掉的节点是 3838

2.2. Examples

Eight Queens

(八皇后问题)在棋盘中找到八个位置放置皇后,使得它们都不同行且不同列,也不能同时位于对角线上。

在游戏树上进行 DFS 搜索。

Turnpike Reconstruction Problem

在一条直线上找到 nn 个地方建立加油站,已知它们两两之间的距离(共 n(n1)2\dfrac{n(n-1)}{2} 对),求出所有加油站的位置,假定第一个加油站的坐标是 00

就是暴搜。在 DFS 过程中维护未分配的距离集合,还有当前的处理区间,每次从距离集合中找到最大的距离 DD,看新的加油站应当放在 x1+Dx_1+D 的位置还是 xnDx_n-D 的位置即可。

Stick Problem

给一个从若干根长度为 LL 的大棍子里切出来的小棍子长度集合,求最小的可能的 LL

从小到大枚举 LL 然后将原来通过回溯法进行搜索。

Tic-tac-toe Game (play with computer)

经典井字棋小游戏。

这里定义 WPlayerW_\text{Player} 为 Player 能够赢得胜利的可能数(如果把剩下所有各自都填上你的棋子,可以有多少个三连),可以一定程度上表征局面对于自己的优劣情况。定义 goodness 函数 f(P)=WAIWPlayerf(P)=W_\text{AI}-W_\text{Player},使用 Minimax 搜索交替进行选手——计算机的对弈,需要使用 αβ\alpha-\beta 剪枝。

3. 分治 Divide & Conquer

  • 分治(divide conquer)

3.1. Complexity Analysis

分析分治算法的复杂度有三种常用的方法:

  • 代换法(substitution method):先猜对答案,然后使用数归证明。
  • 递归树法(recursion-tree method):写成多叉线段树的形式,每一层分别计算,最后加起来。
  • 主方法(master method):用主定理解决。

3.2. Master Theorems

主定理(master theorems)

习题

For each of the following recurrences, choose the one that we cannot apply the Master Theorems to solve.

A. T(n)=3T(n/3)+n/lgnT(n) = 3 T(n/3) +n / \lg n

B. T(n)=4T(n/2)+n/lgnT(n) = 4 T(n/2) +n / \lg n

C. T(n)=4T(n/2)+n2/lgnT(n) = 4 T(n/2) +n^2 / \lg n

D. T(n)=3T(n/4)+nlgnT(n) = 3 T(n/4) +n \lg n

答案

AC?然而 pta 上的答案是 A。

3.3. Examples

Closest Point Problem

给平面上 nn 个点,求解最近点对。

4. 动态规划 Dynamic Programming

  • 背包问题(the knapsack problem)

4.1. Examples

Fibonacci Numbers

an=an1+an2a_n=a_{n-1}+a_{n-2},求解 ana_n

两种实现:启发式搜索或者直接序列 DP,都是用一张表来存 ana_n

Ordering Matrix Multiplications

安排 nn 个矩阵的乘法的计算顺序,最小化计算量。(第 ii 个矩阵 MiM_i 的大小是 ri1×rir_{i-1}\times r_i

区间 DP,f[i][j]=f[i][k]+f[k+1][j]+r[i1]×r[k]×r[j]f[i][j]=f[i][k]+f[k+1][j]+r[i-1]\times r[k]\times r[j]

Optimal Binary Search Tree

nn 个词的搜索频率,应如何构建 BST 以最小化 access 期望代价?相比于 Haffman 编码问题,我们确定了中序遍历,且内部节点上也能有键值。

sHVVVUcH.png

最优子结构转移:最优方案的两棵子树一定是最优方案。定义 wi,j=k=ijpkw_{i,j} =\sum_{k=i}^j p_kci,jc_{i,j} 表示给区间 [i,j][i,j] 节点建树的最小花费,则有转移:

ci,j=minikj{pk+wi,k1+ci,k1+wk+1,j+ck+1,j}=wi,j+min{ci,k1+ck+1,j}c_{i,j} = \min\limits_{i\le k\le j} \{p_k + w_{i,k-1} + c_{i,k-1} + w_{k+1,j} + c_{k+1,j} \} = w_{i,j} + \min \{c_{i,k-1}+c_{k+1,j}\}

All-Pairs Shortest Path

求任意两点间最短路径。

我看了看怎么感觉就是 Floyd 啊?

Product Assembly

nn 步的工序,可以在两条生产线之间切换,消耗的时间和本次及上千次在哪条生产线完成有关,求最优生产流程。

我看了看怎么感觉就是直接 DP 啊?

5. 贪心 Greedy

5.1. Examples

Activity Selection Problem

ZfAxMf1F.png

DP 做法:设 dpidp_{i} 表示前 ii 个单位时间里最多选几个,找到所有 ft1=if_t-1=i 的活动,从 dpst1+1dp_{s_t - 1} + 1 转移。时间复杂度 O(n2)O(n^2),不够优秀。

贪心做法:把所有区间按照右端点排序,每次取右端点最小的,即选择尽早结束的活动(反过来也可,即选择最迟开始的活动),然后把有重合的都删掉,如此循环直到结束。时间复杂度 O(nlogn)O(n\log n)

Huffman Codes

哈夫曼编码问题。

建 Huffman 树的过程正体现了贪心思想。

6. 近似 Approximation

6.1. Approximation Ratio

CC 为我们算法的 cost,CC^\ast 为最优解的 cost,定义近似率(approximation ratio) 为:

max(CC,CC)ρ(n)\max\left(\dfrac{C}{C^\ast},\dfrac{C^\ast}{C}\right) \le \rho(n)
  • 称这样的算法为 ρ(n)\rho(n)-approximation algorithm
  • approximation scheme: 近似率 ρ(n)=1+ϵ\rho(n)=1+\epsilon 的算法,即 (1+ϵ)(1+\epsilon)-approximation algorithm
  • PTAS:polynomial-time approximation scheme 关于 nn 成多项式复杂度的算法 (设 ϵ\epsilon 为常数)
  • FPTAS:fully polynomial-time approximation scheme 关于 nnϵ\epsilon 都成多项式复杂度的 算法

6.2. On-line & Off-line Algorithms

在读入数据的时候进行决策,一旦决策之后不能修改。

6.3. Examples

Approximate Bin Packing

Given NN items of sizes S1,S2,,SNS_{1},S_{2},\cdots,S_{N}, such that 0<Si10<S_i\leq1 for all 1iN1\leq i\leq N. Pack these items in the fewest number of bins, each of which has unit capacity.

——这一问题是 NP-Hard 的。

Next Fit 做法:依次读入每个物品,看看是否能和前一个物品放在同一个 bin,如果不行的话就开一个新 bin。

证明:设最优解为 MM,则用 Next Fit 做法得到的解不超过 2M12M-1

设用 Next Fit 做法生成的解为 2M2M(或 2M+12M+1),那么有 S2i1+S2i>1 (1iM)S_{2i-1}+S_{2i} > 1 \space (1\le i\le M),故 i=12MSi>M\sum_{i=1}^{2M} S_i > M,故至少需要 M+1M+1 个 bin。

First Fit 做法:依次读入每个物品,扫描所有已有的箱子,找到第一个能放下的放,如果不存在则新开一个箱子放。设最优解为 MM,则得到的解不超过 1.7M1.7M

Best Fit 做法:依次读入每个物品,在可以放下这一物品的箱子中选剩余空间最小的,如果不存在则新开一个箱子放。设最优解为 MM,则得到的解不超过 1.7M1.7M

这里的 Next Fit、First Fit 和 Best Fit 做法都是在线做法,如果允许离线,则可将所有物品按照体积从大到小排序,然后应用 First Fit(或 Best Fit)做法。设最优解为 MM,则得到的解不超过 11M+69\dfrac{11 M+6}{9}

The Knapsack Problem (0-1 Version)

就是 0-1 背包问题。

  • 用 DP 解决的复杂度是指数级的,因为物品大小和 nn 不同阶,实际上 Knapsack 问题是 NP-Hard 问题,Knapsack 的判定是 NPC 问题。
  • 如果将物品的大小缩放到 poly(n)poly(n) 的范围,则有多项式复杂度的 DP,但算法也变成了近似算法。

如果使用贪心做法,每次选(可选的)里价值最高或性价比最高的(两种做法分别做一次),可以证明近似比为 22

证明:贪心做法的近似比为 22

这里 PGreedyP_\text{Greedy} 是两种贪心做法得到结果的 max。

The K-center Problem

平面上给定 nn 个点,确定 KK 个圆心的位置覆盖所有点并使最大圆的半径最小。

定理:除非 P=NP\text{P}=\text{NP},否则不存在 ratio<2\text{ratio}<2 的解法。

若 K-center 存在 (2ϵ)(2-\epsilon)-approximation,则可用于精确求解 Dominating Set 问题,而后者是一个 NPC 问题。

7. 局部搜索 Local Search

  • SSS \sim S'SS'SS 的一个相邻解(neighboring solution),只需要对 SS 进行一个微小的修改就可以得到。
  • N(S)N(S)SS邻域(nerghborhood),即 {SSS}\{S'\mid S\sim S'\}
  • SS^\astSS 的 local optimum,即 SN(S)S^\ast\in N(S) 且是其中最优的。

7.1. Gradient Descent

爬山——梯度下降法:每次在邻域中选一个最优的转移,如果找不到则退出。

容易陷入局部最优解中。

7.2. The Metropolis Algorithm

模拟退火——Metropolis 算法:每次在邻域中随机选一个转移,如果比当前情况更有则以一定概率 eΔcostkT-e^{\dfrac{\Delta cost}{k T}} 接收,否则概率接收且这一概率随迭代次数指数下降。

7.3. Examples

Vertex Cover Problem

最小点覆盖问题。

直接使用爬山问题容易陷在 e 局部最优解,建议使用模拟退火算法。

Hopfield Neural Network

给定 G=(V,E)G=(V,E) 其中边权有正负,给每个节点分配一个 su{1,1}s_u\in\{-1,1\},称一个点是 state assignment 当且仅当

state-flipping 算法:每次反转一个不稳定的节点作为转移。

证明:State-flipping 算法一定能达到一个稳定状态,且最多反转 W=eweW = \sum_e |w_e| 次。

Maximal Cut Problem

最大割问题。把点集划分为两部分 A,BA,B,最大化 w(A,B)=uA,vBwu,vw(A,B) = \sum_{u\in A, v\in B} w_{u,v}

采用类似于上一问的转移,即翻转一个点的状态。若进行爬山算法,可以得到一局部最优解 A,BA,B。设最优解为 A,BA^\ast,B^\ast

证明:w(A,B)12w(A,B)w(A,B) \ge \dfrac{1}{2} w(A^\ast, B^\ast)

big-improvement-flip 算法:当新的局部最优解的增长的幅度小于 2εvw(A,B)\dfrac{2\varepsilon}{|v|} w(A,B) 的时候就停止,这样算法可以在一定近似比的代价下保证在多项式复杂度内结束。

定理

这样就有 (2+ε)w(A,B)w(A,B)(2+\varepsilon) w(A,B) \ge w(A^\ast, B^\ast),可以在最多 O(nεlogW)O\left(\dfrac{n}{\varepsilon} \log W\right) 次翻转后结束。

8. 随机化 Randomize

有两种随机算法:

  • 有非常高的概率给出正确答案。efficient randomized algorithms that only need to yield the correct answer with high probability
  • 总是正确的,并在期望中运行的很有效率。 randomized algorithms that are always correct, and run efficiently in expectation

8.1. Random Shuffle

给每个元素分配一个随机的 key:a[i].key = rng() % (n * n * n),然后根据 key 进行排序。根据生日碰撞,这里取 N3N^3 作为模数就能有一个不错的效果。

8.2. Examples

The Hiring Problem

  • Hire an office assistant from headhunter.
  • Interview a different applicant per day for NN days.
  • Interviewing Cost = CiC_{i} \ll Hiring Cost =Ch=C_{h}
  • Analyze interview & hiring cost instead of running time
  • Assume MM people are hired. Total Cost: O(NCi+MCh)O(N C_{i} + M C_{h}).

总花费 = 面试次数 ×\times 每次面试的花费 ++ 雇佣人数 ×\times 雇佣费用。

一种简单的做法:看到比先前更好的人就雇佣,但是在面试者按照优秀程度递增顺序进来的时候就会爆炸。不妨进行随机排序,则期望花费为 O(ChlnN+NCi)O(C_h \ln N + N C_i)

Online Hiring Problem - Hire at Once

将前面的问题改为在线,但只能雇佣一次。

一种较高概率成功的解:先面试前 kk 个人但一定不从中雇佣,然后依次面试第 k+1Nk+1\cdots N 个人,其中第一个满足比前 kk 个人优秀即 Aj=maxi=1kAiA_j = \max_{i=1}^k A_i 的人进行雇佣。可以证明取 k=Nek = \dfrac{N}{e} 时最优。

证明:最优解 k=Nek = \dfrac{N}{e}

根据微积分的知识我们有:

lnNlnk=kN1xdxi=kN11ik1N11idx=ln(N1)ln(k1)\ln N-\ln k = \int_k^N \dfrac{1}{x}\text dx \le \sum_{i=k}^{N-1} \dfrac{1}{i} \le \int_{k-1}^{N-1} \dfrac{1}{i} \text dx = \ln (N-1) - \ln(k-1)

那么取到最优解的概率为:

Pr[S]=i=k+1NPr[Si]=kNi=kN11ikNln(Nk)Pr[S] = \sum_{i=k+1}^N Pr[S_i] = \dfrac{k}{N} \sum_{i=k}^{N-1} \dfrac{1}{i} \sim \dfrac kN \ln \left(\dfrac Nk\right)

根据高中数学的知识可以知道取 Nk=e\dfrac N k=e 时最大即 k=Nek=\dfrac{N}{e},且概率为 1e\dfrac{1}{e}

Quicksort

众所周知,直接选中间位置作为 pivot 的快速排序是可以被卡到 O(n2)O(n^2) 的,那应该怎么选呢。

随机一个数作为 pivot,但如果这一 pivot 是最小的 1/4 或最大的 1/4 则重选,期望意义下只重选一次。

这样至少会将规模划分为 n4\dfrac{n}{4}3n4\dfrac{3n}{4},可以证明复杂度是 O(nlogn)O(n\log n)

9. 并行算法 Parallel Algorithm

两个模型:Parallel Random Access Machine (PRAM);Work-Depth (WD)。

9.1. PRAM Model

yfN9mtsC.png

fN50Vo13.png

9.2. WD Model

HrnJ84fN.png

【WD-presentation Sufficiently Theorem】An algorithm in the WD mode can be implememnt by any P(n)P(n) processors within O(W(n)/P(n)+T(n))O(W(n)/P(n) + T(n)) time, using the same concurrent-write convention as in the WD presentation.

Maximal Finding

nn 个数的最大值,并行算法。

  • Replace "+" by "max" in the summation algorithm. T(n)=O(logn), W(n)=O(n)T(n)=O(\log n),\ W(n)=O(n)
  • Compare al pairs (find B(i)=0B(i)=0). T(n)=O(1), W(n)=O(n2)T(n)=O(1),\ W(n)=O(n^{2})
  • Doubly-logarithmic Paradigm: Parition by n1/2n^{1/2}. T(n)=O(loglogn), W(n)=O(nloglogn)T(n)=O(\log \log n),\ W(n)=O(n \log \log n)
  • Paritition by h=loglognh=\log \log n. T(n)=O(loglogn), W(n)=O(n)T(n) = O(\log \log n),\ W(n) =O(n)
  • Random Sampling. n7/8=n3/4×n1/8, n3/4=n1/2×n1/4n^{7/8}=n^{3/4} \times n^{1/8},\ n^{3/4}=n^{1/2} \times n^{1/4}. M(n7/8)T=O(1), W=O(n)M(n^{7/8}) \sim T = O(1),\ W=O(n).

10. 外部排序 External Sorting

我们只有有限的内存(只能存放 MM 个数)和若干 tape(一种特殊的存储结构,只能顺序读写),需要解决排序问题。

这个具体的过程特别抽象我懒得记录了,可以看一下别人的笔记。不过别因为这个是最后一讲就不看了,似乎是每年必考的内容。

评论

TABLE OF CONTENTS

1. 倒排索引 Inverted File Index
1.1. Optimize a Search Engine
2. 回溯 Backtracing
2.1. Minimax Search & α-β Pruning
2.2. Examples
3. 分治 Divide & Conquer
3.1. Complexity Analysis
3.2. Master Theorems
3.3. Examples
4. 动态规划 Dynamic Programming
4.1. Examples
5. 贪心 Greedy
5.1. Examples
6. 近似 Approximation
6.1. Approximation Ratio
6.2. On-line & Off-line Algorithms
6.3. Examples
7. 局部搜索 Local Search
7.1. Gradient Descent
7.2. The Metropolis Algorithm
7.3. Examples
8. 随机化 Randomize
8.1. Random Shuffle
8.2. Examples
9. 并行算法 Parallel Algorithm
9.1. PRAM Model
9.2. WD Model
10. 外部排序 External Sorting