分治的引入
首先先来看一个经典的问题:在16个硬币中有1个假币,假币的重量比较轻,现在有一个天平,天平上两端可以放任意硬币请问怎么样能够快速找出那个假币?
小白思维:随便找一个硬币放天平一遍,其余15个按个放在天平右边,则最多15次能找到假币
更快捷的思维:
- 把16个硬币找假币的问题 简称为16问题
- 将硬币分为2组,即问题为在2组每组为8枚硬币中找出轻的那组 即变为8问题
- 将8枚硬币再分为2组,每组4个,则可以找到轻的那组,即可以划分为4问题
- 同样的步骤,上述问题划分为2问题
- 比较得出结果。共计4次找出假币
分治
分治全称为分而治之,即把原问题划分为若干个规模较小而结构和原问题相似的子问题,然后分别解决这些子问题,最后合并子问题的解,即可得到原问题的解。
上面的定义体现了分治算法的三个步骤
- 分解:划分为若干和原问题拥有相同或相似结构的子问题
- 解决:递归解决所有子问题
- 合并:子问题的解合并为原问题的解
分治作为一种算法思想,可以用递归的手段实现,也可以用非递归的手段解决,一般用递归,当然具体问题具体分析。
递归
递归必备的2个元素
递:递归式或递归调用
归:递归边界
学习递归,一定要不断思考 递 和 归 ,多多体会。
n阶乘问题
思考:n阶乘 即n* n-1* n-2*n-3…*1
递:递归调用,将求阶乘视为函数,函数每次运算的结果给下次运算,这就是递 即 n!=n * (n-1)!
归:n=0时结束
#include <cstdio>
int fun(int n);
using namespace std;
int main(){
long long n;
scanf("%d",&n);
printf("%d",fun(n));
return 0;
}
int fun(int n){
if(n==0) return 1;
else return n*fun(n-1);
}
Fibonacci(斐波那契数列)
数列:1,1,2,3,5,8,13,21,…
满足 f(0)=1,(1)=1,f(n)=f(n-1)+f(n-2)(n>=2)的数列。
递:f(n)=f(n-1)+f(n-2)(n>=2)
归: f(0)=1,(1)=1
问题:求出第n项的值(n从0开始)
#include <cstdio>
int fun(int n);
using namespace std;
int main(){
int n;
scanf("%d",&n);
printf("%d",fun(n));
return 0;
}
int fun(int n){
if(n==0||n==1) return 1;
else return fun(n-1)+fun(n-2);
}