分治法的套路

参考视频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小元素

第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

4.L型组件填图

L型组件填图

L组件填图问题 1.问题描述 设B是一个n×n棋盘,n=2k,(k=1,2,3,…)。用分治法设计一个算法,使得:用若干个L条块可以覆盖住B的除一个特殊方格外的所有方格。其中,一个L条块可以覆盖3个方格。且任意两个L条块不能重叠覆盖棋盘。 例如:如果n=2,则存在4个方格,其中,除一个方格外,其余3个方格可被一L条块覆盖;当n=4时,则存在16个方格,其中,除一个方格外,其余15个方格被5个L条块覆盖。 2. 具体要求 输入一个正整数n,表示棋盘的大小是n*n的。输出一个被L条块覆盖的n*n棋盘。该棋盘除一个方格外,其余各方格都被L条块覆盖住。为区别出各个方格是被哪个L条块所覆盖,每个L条块用不同的数字或颜色、标记表示。 3. 测试数据(仅作为参考) 输入:8 输出:A 2 3 3 7 7 8 8 2 2 1 3 7 6 6 8 4 1 1 5 9 9 6 10 4 4 5 5 0 9 10 10 12 12 13 0 0 17 18 18 12 11 13 13 17 17 16 18 14 11 11 15 19 16 16 20 14 14 15 15 19 19 20 20 4. 设计与实现的提示 对2k×2k的棋盘可以划分成若干块,每块棋盘是原棋盘的子棋盘或者可以转化成原棋盘的子棋盘。 注意:特殊方格的位置是任意的。而且,L条块是可以旋转放置的。 为了区分出棋盘上的方格被不同的L条块所覆盖,每个L条块可以用不同的数字、颜色等来标记区分。 5. 扩展内容 可以采用可视化界面来表示各L条块,显示其覆盖棋盘的情况。 经典的递归问题, 这是我的大代码, 只是本人很懒, 不想再优化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值