python 实现分治法的几个例子
分治法所能解决的问题一般具有以下几个特征:
1) 该问题的规模缩小到一定的程度就可以容易地解决2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。3) 利用该问题分解出的子问题的解可以合并为该问题的解;4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。
第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;
第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归思想的应用;、
第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。
第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。
题目1. 给定一个顺序表,编写一个求出其最大值的分治算法。
# 基本子算法(子问题规模小于等于 2 时)
def get_max(max_list):return max(max_list) # 这里偷个懒!# 分治法 版本一
def solve(init_list):n = len(init_list)if n <= 2: # 若问题规模小于等于 2,最终解决return get_max(init_list)# 分解(子问题规模为 2,最后一个可能为 1)temp_list=(init_list[i:i+2] for i in range(0, n, 2))# 分治,合并max_list = list(map(get_max, temp_list))# 递归(树)solve(max_list)# 分治法 版本二
def solve2(init_list):n = len(init_list)if n <= 2: # 若问题规模小于等于 2,解决return get_max(init_list)# 分解(子问题规模为 n/2)left_list, right_list = init_list[:n//2], init_list[n//2:]# 递归(树),分治left_max, right_max = solve2(left_list), solve2(right_list)# 合并return get_max([left_max, right_max])if __name__ == "__main__":# 测试数据test_list = [12,2,23,45,67,3,2,4,45,63,24,23]# 求最大值print(solve(test_list)) # 67print(solve2(test_list)) # 67
题目2. 给定一个顺序表,判断某个元素是否在其中。
# 子问题算法(子问题规模为 1)
def is_in_list(init_list, el):return [False, True][init_list[0] == el]# 分治法
def solve(init_list, el):n = len(init_list)if n == 1: # 若问题规模等于 1,直接解决return is_in_list(init_list, el)# 分解(子问题规模为 n/2)left_list, right_list = init_list[:n//2], init_list[n//2:]# 递归(树),分治,合并res = solve(left_list, el) or solve(right_list, el)return resif __name__ == "__main__":# 测试数据test_list = [12,2,23,45,67,3,2,4,45,63,24,23]# 查找print(solve2(test_list, 45)) # Trueprint(solve2(test_list, 5)) # False
题目3. 找出一组序列中的第 k 小的元素,要求线性时间
# 划分(基于主元 pivot),注意:非就地划分
def partition(seq):pi = seq[0] # 挑选主元lo = [x for x in seq[1:] if x <= pi] # 所有小的元素hi = [x for x in seq[1:] if x > pi] # 所有大的元素return lo, pi, hi# 查找第 k 小的元素
def select(seq, k):# 分解lo, pi, hi = partition(seq)m = len(lo)if m == k: return pi # 解决!elif m < k: return select(hi, k-m-1) # 递归(树),分治else:return select(lo, k) # 递归(树),分治if __name__ == '__main__':seq = [3, 4, 1, 6, 3, 7, 9, 13, 93, 0, 100, 1, 2, 2, 3, 3, 2]print(select(seq, 3)) #2print(select(seq, 5)) #2
题目4. 快速排序
# 划分(基于主元 pivot),注意:非就地划分
def partition(seq):pi = seq[0] # 挑选主元lo = [x for x in seq[1:] if x <= pi] # 所有小的元素hi = [x for x in seq[1:] if x > pi] # 所有大的元素return lo, pi, hi# 快速排序
def quicksort(seq):# 若问题规模小于等于1,解决if len(seq) <= 1: return seq# 分解lo, pi, hi = partition(seq)# 递归(树),分治,合并return quicksort(lo) + [pi] + quicksort(hi)seq = [7, 5, 0, 6, 3, 4, 1, 9, 8, 2]
print(quicksort(seq)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
题目5. 合并排序(二分排序)
# 合并排序
def mergesort(seq):# 分解(基于中点)mid = len(seq) // 2left_seq, right_seq = seq[:mid], seq[mid:]# 递归(树),分治if len(left_seq) > 1: left_seq = mergesort(left_seq)if len(right_seq) > 1: right_seq = mergesort(right_seq)# 合并res = []while left_seq and right_seq: # 只要两者皆非空if left_seq[-1] >= right_seq[-1]: # 两者尾部较大者,弹出res.append(left_seq.pop())else: res.append(right_seq.pop())res.reverse() # 倒序return (left_seq or right_seq) + res # 前面加上剩下的非空的seqseq = [7, 5, 0, 6, 3, 4, 1, 9, 8, 2]
print(mergesort(seq)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
题目6. 汉诺塔
# 汉诺塔
def move(n, a, buffer, c):if n == 1:print(a,"->",c)#returnelse:# 递归(线性)move(n-1, a, c, buffer)move(1, a, buffer, c) # 或者:print(a,"->",c)move(n-1, buffer, a, c)move(3, "a", "b", "c")
问题7. 爬楼梯
假设你正在爬楼梯,需要n步你才能到达顶部。但每次你只能爬一步或者两步,你能有多少种不同的方法爬到楼顶部?
# 爬楼梯
def climb(n=7):if n <= 2:return nreturn climb(n-1) + climb(n-2) # 等价于斐波那契数列!print(climb(5)) # 8
print(climb(7)) # 21
问题8. 给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。(最近点对问题)
from math import sqrt# 蛮力法
def solve(points):n = len(points)min_d = float("inf") # 最小距离:无穷大min_ps = None # 最近点对for i in range(n-1):for j in range(i+1, n):d = sqrt((points[i][0] - points[j][0])**2 + (points[i][1] - points[j][1])**2) # 两点距离if d < min_d:min_d = d # 修改最小距离min_ps = [points[i], points[j]] # 保存最近点对return min_ps# 最接近点对(报错!)
def nearest_dot(seq):# 注意:seq事先已对x坐标排序n = len(seq)if n <= 2: return seq # 若问题规模等于 2,直接解决# 分解(子问题规模n/2)left, right = seq[0:n//2], seq[n//2:]print(left, right)mid_x = (left[-1][0] + right[0][0])/2.0# 递归,分治lmin = (left, nearest_dot(left))[len(left) > 2] # 左侧最近点对rmin = (right, nearest_dot(right))[len(right) > 2] # 右侧最近点对# 合并dis_l = (float("inf"), get_distance(lmin))[len(lmin) > 1]dis_r = (float("inf"), get_distance(rmin))[len(rmin) > 1]d = min(dis_l, dis_r) # 最近点对距离# 处理中线附近的带状区域(近似蛮力)left = list(filter(lambda p:mid_x - p[0] <= d, left)) #中间线左侧的距离<=d的点right = list(filter(lambda p:p[0] - mid_x <= d, right)) #中间线右侧的距离<=d的点mid_min = []for p in left:for q in right:if abs(p[0]-q[0])<=d and abs(p[1]-q[1]) <= d: #如果右侧部分点在p点的(d,2d)之间td = get_distance((p,q))if td <= d: mid_min = [p,q] # 记录p,q点对d = td # 修改最小距离if mid_min:return mid_minelif dis_l>dis_r:return rminelse:return lmin# 两点距离
def get_distance(min):return sqrt((min[0][0]-min[1][0])**2 + (min[0][1]-min[1][1])**2)def divide_conquer(seq):seq.sort(key=lambda x:x[0])res = nearest_dot(seq)return res# 测试
seq=[(0,1),(3,2),(4,3),(5,1),(1,2),(2,1),(6,2),(7,2),(8,3),(4,5),(9,0),(6,4)]
print(solve(seq)) # [(6, 2), (7, 2)]
#print(divide_conquer(seq)) # [(6, 2), (7, 2)]
问题8. 从数组 seq 中找出和为 s 的数值组合,有多少种可能
'''
求一个算法:N个数,用其中M个任意组合相加等于一个已知数X。得出这M个数是哪些数。比如:
seq = [1, 2, 3, 4, 5, 6, 7, 8, 9]
s = 14 # 和全部可能的数字组合有:
5+9, 6+8
1+4+9, 1+5+8, 1+6+7, 2+3+9, 2+4+8, 2+5+7, 3+4+7, 3+5+6
1+2+5+6, 1+3+4+6, 1+2+4+7, 1+2+3+8, 2+3+4+5
共计15种http://club.excelhome.net/thread-443533-1-1.html'''
# 版本一(纯计数)
def find(seq, s):n = len(seq)if n==1:return [0, 1][seq[0]==s]if seq[0]==s:return 1 + find(seq[1:], s)else:return find(seq[1:], s-seq[0]) + find(seq[1:], s)# 测试
seq = [1, 2, 3, 4, 5, 6, 7, 8, 9]
s = 14 # 和
print(find(seq, s)) # 15seq = [11,23,6,31,8,9,15,20,24,14]
s = 40 # 和
print(find(seq, s)) #8# 版本二 (打印)
def find2(seq, s, tmp=''):if len(seq)==0: # 终止条件returnif seq[0] == s: # 找到一种,则print(tmp + str(seq[0])) # 打印find2(seq[1:], s, tmp) # 尾递归 ---不含 seq[0] 的情况find2(seq[1:], s-seq[0], str(seq[0]) + '+' + tmp) # 尾递归 ---含 seq[0] 的情况# 测试
seq = [1, 2, 3, 4, 5, 6, 7, 8, 9]
s = 14 # 和
find2(seq, s)
print()seq = [11,23,6,31,8,9,15,20,24,14]
s = 40 # 和
find2(seq, s)
python 实现分治法的几个例子相关推荐
- python应用——分治法实现循环赛
一.要求 用分治法实现循环赛: 一共有n个选手要进行循环赛,请设计一个满足以下要求的比赛日程表: (1)每个选手必须与其他n-1个选手各赛一次: (2)每个选手一天只能赛一次: (3)当n 是偶数,循 ...
- Python算法——分治法查找数组中元素最小最大值
要求: 给定数组a1,a2,a3,...an,找出数组中最大值和最小值.(数组中两两各不相同) 分析: 算法思想类似于上图,将数组两两分为一组,如果数组元素奇数个,就把最后一个元素单独分为一组,然后分 ...
- python求最大值代码的方式_python使用分治法实现求解最大值的方法
本文实例讲述了python使用分治法实现求解最大值的方法.分享给大家供大家参考.具体分析如下: 题目: 给定一个顺序表,编写一个求出其最大值和最小值的分治算法. 分析: 由于顺序表的结构没有给出,作为 ...
- PYTHON:大整数乘法(分治法)
何为分治法: 分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同.求出子问题的解,就可得到原问题的解.即一种分目标完成程序算法,简单问题可用二分法 ...
- python分治算法_分治法及其python实现例子
在前面的排序算法学习中,归并排序和快速排序就是用的分治法,分治法作为三大算法之一的,有非常多的应用例子. 分治法概念 将一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题-- ...
- python分治算法_python算法实现-分治法
分治法概念将一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题----"分" 将最后子问题可以简单的直接求解----"治" 将所有子问 ...
- [转载] 算法导论:分治法,python实现合并排序MERGE-SORT
参考链接: Python中的合并排序merge sort 1. 简单合并排序法实现 思想:两堆已排好的牌,牌面朝下,首先掀开最上面的两张,比较大小取出较小的牌,然后再掀开取出较小牌的那一堆最上面的牌和 ...
- 算法--分治法归并排序 python
设计算法 我们可以选择使用的算法设计方法有很多,插入排序使用了增量方法:在排序子数组A[1-j-1]后,将单个元素A[ j ]插入子数组的适当位置,产生排序好的子数组A[1-j]. 而这次我们将考查另 ...
- python分治算法_Python算法:分治法
本节主要介绍分治法策略,提到了树形问题的平衡性以及基于分治策略的排序算法 本节的标题写全了就是:divide the problem instance, solve subproblems recur ...
最新文章
- wordpressPHP实现ajax评论,AJAX_wordpress 为主题添加AJAX提交评论功能的php代码,首先需要在主题的function.php文 - phpStudy...
- 动词ing基本用法_百因必有果,你的“福利”就是我第61篇:过去进行时构成及用法...
- jupyter 数据分析可视化案例_Python数据分析及可视化实例之Anaconda、Jupyter简介
- Linux关机命令和重启命令
- HDU 3549 Flow Problem (网络流板子)
- 使用ArrayList时设置初始容量的重要性
- [Kesci] 预测分析 · 客户购买预测(AUC评估要使用predict_proba)
- 下取整函数的含义_取整函数解读
- java glob paths_java – 使用getPathMatcher的Glob模式
- 设计【SPFA】【差分约束】
- 制造业执行系统MES 在汽车零配件行业展露锋芒
- 【win10】win10开机黑屏时间长或只有鼠标解决办法,亲测可用
- REASON: Ambari Server java process has stopped. Please check the logs for more information.
- prompt综述(截至2021.12.1)
- 《大数据时代》(维克托·迈尔·舍恩伯格)读书笔记
- CSS盒子模型(内容区、边框、内外边距)
- Ant Design Icon图标使用
- 橘子学Flink03之Flink的流处理与批处理
- 软件人眼中的APP的产品定位
- 数据可视化(python)----中国近十年就业GDP对比
热门文章
- ttcp 之测试网络性能
- python0.1+0.2_为什么0.1+0.2=0.30000000000000004
- jdk动态代理实例和cglib动态代理实例_CGLib 动态代理 原理解析
- python 自动化框架打包_听说很多人都不会打包,教你Python实现前端自动化打包部署!...
- oracle 10g 连接语句,Oracle 10g数据库基础之基本查询语句-下-连接子查询
- 关于python那些事_Python 入门你必须知道的那些事
- 挑战马斯克的Neuralink,另一家神秘的「脑机接口」公司已获投资
- 发力大陆移动VR,HTC刚刚发布ViveWave开放平台和ViveFocus一体机
- 德赛西威与智驾科技MAXIEYE发布“九逵计划”,部署商用车自动驾驶技术及服务...
- 北理工副教授曝学生论文被100%抄袭,对方为南方某985学生,该校抄袭事件还不止一起...