参考视频bilibil fjnuzs
一、分治思想
将原问题分解成若干个相互独立的与原问题性质相同的子问题,子问题还用相同的分治方法解,分治过程一直进行下去,直至子问题的规模充分小,可直接解为止。并将这些子问题的解组合起来得到原问题的解。和递归有相似又有区别,这里的子问题可以不是递归的只有一个。但是分治确实带有递归的特性。
二、分治模板和时间复杂度
divideandconquer(P) //用分治法求问题P的解
if|P|<=n0 then // |P|表示问题P的规模
y=ds(P) //ds为直接求解问题的算法
return y
else
divide(P, P1, P2..... Pk) //将P分解为子问题P1, P.... Pk
fori=1 to k
yi=divideandconquer(Pi) //递归求解子问题
return merge(y1, y2... yk) //merge为组合子问题解的算法
end if
end divideandconquer
C ( n ) = { d n = n 0 a C ( n / c ) + g ( n ) n > n 0 C(n)= \begin{cases} d&n=n_0 \\ aC(n/c)+g(n)&n>n_0 \\ \end{cases} C(n)={daC(n/c)+g(n)n=n0n>n0
n:问题的规模。
n0:可直接解的问题规模的阈值。
a:分解出的需要求解的子问题的个数。
n/c:分解出的子问题的规模。
g(n):分解规模为n的问题以及组合相应子问题的解所需的时间。
d:直接解规模为n0的问题所需的时间。
三、按照模板写的几个分治的列子
1.归并排序
2.第K小元素
3.最近点对问题
题目大概就是给一堆平面上点的坐标,问最近的两个点的距离。
怎么做哩。先X坐标排序,从中间分成两部分,左子问题右子问题递归,返回的是左右两部分的最短距离,合并的时候算中间交界线左右的最短距离。而且算中间段的时候,每个点只用算当前点坐标向下数Y坐标最近的7个点。因为从左右递归已经返回了δ作为当前最小值,那么在下图黑色矩形区域最多左右各自四个点,(反证,如果左边或右边有多于四个点,那最短距离就不是这个δ了)。于是我们每个点最多最多比较与它Y轴坐标相近的7个点。
具体细节我们看伪代码
//求S[low..high]中最近点对的距离并返回。
cp(low, high)
if high-low+1 <= 3 then
用直接方法求S[low.high]中最近点对的距离δ
else
mid= (low+high)/2 //分解
δl=cp(low, mid) //递归
δr=cp(mid+1, high)
δ=min{δl , δr}
x0=x(S[mid]) //那条中轴线的坐标
//以下为组合步骤,即是计算中线左右的点是否存在更短的距离
k=0
for i=1 to n //从Y中抽取集合T,集合T距离中轴线距离小于δ才有可能产生比δ更小的点对
if |x(Y[i])-x0|<=δ then
k= k+1 //k是T的大小
T[k]=Y[i]
end if
end for
δ'=δ //将δ'初始化
for i=1 to k-1 //计算δ'
for j=i+1 to min{i+7, k}
if d(T[i], T[j])< δ' then δ'= d(T[i], T[j])
end for
end for
δ=δ'
end if
return δ
end cp