分治策略:
- 将原始问题划分或者归结为规模较小的子问题
- 递归或迭代求解每个子问题
- 将子问题的解综合得到原问题的解
注:
- 子问题与原问题性质完全一样
- 子问题之间可彼此独立地求解
- 递归停止时子问题可直接求解
算法的一般描述:
Divide-and-Conquer§
时间复杂度函数的递推方程:
W(n)=W(|P1|)+W(|P2|)+…+W(|Pk|)+f(n)
W(c)=C
- P1,P2,…,Pk为划分后产生的子问题
- f(n)为划分子问题以及将子问题的解,综合得到原问题解的总工作量
- 规模为c的最小子问题的工作量为C
两类常见递推方程:
该类递推方程适用于子问题按常数项减少,其中i是每次划分的子问题大小,ai表示子问题的个数,g(n)为分解过程和综合解的工作量。求解可使用迭代法、递归树
该类递推方程适用于子问题按倍数缩小,其中b是缩小的倍数,a表示子问题的个数,d(n)为分解过程和综合解的工作量。求解可使用迭代法、换元法、递归树、主定理
当d(n)为常数:
a != 1,则T(n)=O(n^logba)
a = 1,则T(n)=O(logn)
当d(n)=cn,其中c为常数
a < b,则T(n)=O(n)
a = b,则T(n)=O(nlogn)
a > b,则T(n)=O(n^logba)
分治算法的优化
分治算法递推式:W(n)=aW(n/b)+f(n)或W(n)=aW(n-i)+f(n)
- 减少子问题数。即减少递推式的中a的大小,利用子问题间的依赖关系,是某些子问题的解通过组合其他子问题的解而得到。适用于子问题个数多,划分和综合的工作量不大,复杂度函数W(n)=Θ(n^logba)
例:输入:X,Y是n位二进制数,n=2k。输出:XY
普通乘法:O(n2)
划分:令X=A2n/2+B,Y=C2n/2+D
XY=AC2n+(AD+BC)2n/2+BD
优化前算法复杂度:W(n)=4W(n/2)+O(n)=O(n2),时间复杂度未发生变化
优化:AD+BC=(A-B)(D-C)+AC+BD,其中A-B和D-C都不会超过n/2位,AC和BD是原有的子问题
优化后算法复杂度:W(n)=3W(n/2)+O(n)=O(nlog3)
- 增加预处理。即减少递推式中f(n)的工作量
二分检索
设计思想:
- 通过x与中位数比较,将原问题归结为规模减半的子问题,如果x小于中位数,则子问题由小于x的数构成,否则子问题由大于x的数构成
- 对子问题进行二分检索
- 当子问题规模为1时,直接比较x与T[m],若相等则返回m,否则返回0
算法:BinarySearch(T,l,r,x)
输入:有序数组T;下标从 l 到 r ;检索元素 x
输出:若 x 在T中,输出下标 j ;否则输出 -1
伪码:
c++:
#include<iostream>
using namespace std;
const int n = 10;
int T[n] = {
-2, 0, 8, 13, 20, 29, 35, 44, 50, 58 }; //有序数组
int BinarySearch(int *T, int l, int r, int x){
int m;
while(l <= r){
m = (l + r) / 2;
if(T[m] == x){
return m;
}else if(T[m] > x){
r = m - 1;
}else{
l = m + 1;
}
}
return -1;
}
int main