分治(divide and conquer),全称分而治之,是一种非常重要且常见的算法策略。分治通常基于递归实现,包括“分”和“治”两个步骤。
- 分(划分阶段) :递归地将原问题分解为两个或多个子问题,直至到达最小子问题时终止。
- 治(合并阶段) :从已知解的最小子问题开始,从底至顶地将子问题的解进行合并,从而构建出原问题的解。
如图 12-1 所示,“归并排序”是分治策略的典型应用之一。
- 分:递归地将原数组(原问题)划分为两个子数组(子问题),直到子数组只剩一个元素(最小子问题)。
- 治:从底至顶地将有序的子数组(子问题的解)进行合并,从而得到有序的原数组(原问题的解)。
如何判断分治问题¶
一个问题是否适合使用分治解决,通常可以参考以下几个判断依据。
- 问题可以分解:原问题可以分解成规模更小、类似的子问题,以及能够以相同方式递归地进行划分。
- 子问题是独立的:子问题之间没有重叠,互不依赖,可以独立解决。
- 子问题的解可以合并:原问题的解通过合并子问题的解得来。
显然,归并排序满足以上三个判断依据。
- 问题可以分解:递归地将数组(原问题)划分为两个子数组(子问题)。
- 子问题是独立的:每个子数组都可以独立地进行排序(子问题可以独立进行求解)。
- 子问题的解可以合并:两个有序子数组(子问题的解)可以合并为一个有序数组(原问题的解)
第一题:汉诺塔
def hannuota(n:int):
#f(1)=1 f(2)=3 f(3)=7 f(4)=15
if n ==1:
return 1
else:
return 2*hannuota(n-1)+1
if __name__ == '__main__':
n=64
print(hannuota(n))
###print(2**64-1) 居然是幂次方关系。。。。。。学到了!!
第二题:汉诺塔2
def hannuota(n,a,b,c): #n代表当前移动盘子数量
global sum
#f(1)=1 f(2)=3 f(3)=7 f(4)=15
if n == 1:
sum+=1
if sum == M:
print(f"#{n}: {a}->{c}") #n代表当前移动的盘子
else:
hannuota(n-1,a,c,b)
sum += 1
if sum == M:
print(f"#{n}: {a}->{c}")
hannuota(n - 1, b, a, c)
if __name__ == '__main__':
N,M=map(int,input().split())
sum = 0
hannuota(N,"A",'B','C')
print(sum)