分治思想是一种追求高效率的算法思想。
基本概念
分治,分而治之,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这种朴素的思想来源于人们生活与工作的经验,也完全适用于技术领域。
适用条件
1、问题的规模缩小到一定的规模就可以较容易地解决。
2、问题可以分解为相同类型的子问题,具有最优子结构性质。
3、合并问题分解出的子问题的解可以得到问题的解。
4、问题所分解出的各个子问题之间是独立的,即子问题之间不存在公共的子问题。当然也可以有,但是会降低效率,在出现众多重复子问题的时候常使用动态规划dp。
例题分析
题目题干:
给定一个正整数,求出该数的所有的划分方式。
比如4的划分方法为:4,4=1+3,4=1+1+2,4=2+2,4=1+1+1+1
PS:1+3=4,3+1=4被认为是同一种划分方案
Input
输入需要划分的数字和最大加数,均为正整数。
Output
输出一个正整数,表示划分总数。
解题思路:
对整数进行划分,可以马上想到分治,既然是分治,就要找子问题。假设n是要划分的数,m是最大的加数,n=4,m=3。
将原问题分解成两类子问题,一类是有m的情况,另一类是没有m的情况。然后将有m的情况继续划分,分解成有m-1和没有m-1的情况,一直划分下去,直到m=1。
比如n=4,m=3,划分成的子问题:有3,无3,有2,无2,有1,无1,将这些子问题逐个击破后再合并就能解决大的问题了。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int devide(int n, int m) // n表示需要划分的数字,m表示最大的加数不超过m
{
if(m==1 || n==1) // 若需要划分的数字为1,那么划分的方法数只有一种
{
return 1;
}
else if(n==m && n>1) // 二者相等且大于1的时候,需要让m-1,函数递归后加一 ,转换成n>m的情况
{
return devide(n,n-1)+1;
}
else if(n<m) // 如果n<m,那么令m=n就行,因为最大加数在逻辑上不可能超过n
{
return devide(n,n);
}
else if(n>m)
{
return devide(n,m-1)+devide(n-m,m); // 分为两种:划分方案没有m的情况和划分方案有m的情况
}
return 0;
}
int main()
{
cout<<"请输入需要划分的数字和最大加数:"<<endl;
int n, m;
cin>>n>>m;
int a=devide(n,m);
cout<<a<<endl;
return 0;
}