递归案例-正整数划分

如果你对其他算法或者案例感兴趣,请考虑阅读我的以下文章。

递归案例-汉诺塔.
递归案例-全排列.
动态规划案例-矩阵连乘(含表格填写、问题理解、实例解决).
动态规划案例-最长公共子序列(含表格填写、问题理解、实例解决、例题答案).
递归案例-电路布线(含表格填写等超详细,纯人话讲解).


通过对网上一些大神博主的文章的学习,加上自己的理解,简单解决一下这个案例。

问题

将正整数n表示成一系列正整数之和: n=n1+n2+…+nk, 其中n1≥n2≥…≥nk≥1,k≥1。正整数n的这种表示称为正整数n的划分。求正整数n的不同划分个数。
对于这个问题,我们可以通过一个例子来理解它。
eg:正整数6的划分
6
5+1
4+2;4+1+1
3+3;3+2+1;3+1+1+1
2+2+2;2+2+1+1;2+1+1+1+1
1+1+1+1+1+1

问题分析

为什么要用递归

递归的定义:函数调用自身。
我认为运用递归的条件就是:每一步进行的操作基本相同,并且问题规模逐渐减小。
通过上面的例子,我们可以看出,6的划分个数=以5为界限对6划分的个数+(6),每一个子问题的操作基本相同,并且问题规模在不断减小。

函数理解

我们可以用p(n,m)来表示以m为界限(划分的数不能超过m)对n进行划分的个数
有点难理解?
举个例子
p(6,3)=
(3+3);(3+2+1);(3+1+1+1)
(2+2+2);(2+2+1+1);(2+1+1+1+1)
(1+1+1+1+1+1)
=7

情况分析

对于实际情况我们可能会遇到以下的情况:
1.m>n p(n,m) 理解:以m为界限对n进行划分,这种情况也就等于p(n,n)。例如以6为界限和以7为界限对6所得到的划分都是一样的。
eg:p(6,7)=p(6,6)。
2. n =1 p(1,m) 理解:以m为界限对1进行划分,那么这种情况只有一种,也就是1。eg:p(1,2)=p(1,1)=1。
3.m=1 p(n,1) 理解:以1为界限对n进行划分,那么这种情况也只有一种,也是1。
eg:p(3,1) = (1+1+1)=1。
4.m=n p(n,n) 理解:以n为界限对n进行划分。这种情况下它等于p(n,n-1)+1。
eg:p(6,6) = (6) + p(6,5)
5.m<n p(n,m) 理解:以m为界限对n进行划分。这种情况下它等于p(n,m-1)+p(n-m,m)1。这个比较难理解。他可以理解为以m为界限对n的划分=以m-1为界限对n的划分+含m时对n的划分

eg:p(6,3)=p(n,m-1)+p(n-m,m)
=p(6,2)+p(3,3)
={ (2+2+2),(2+2+1+1),(2+1+1+1+1),(1+1+1+1+1+1) }+{ (3+3),(3+2+1),(3+1+1+1) }

代码演示

通过对不同情况的分析,我们写出递归函数。
递归函数代码:

public static int p(int n,int m)
 {
  if(n<=0)
   return 0;
  else if(n==1||m==1)
   return 1;
  else if(m>n)
   return p(n, n);
  else if(m==n)
   return 1+p(n, n-1);
  else
   return p(n, m-1)+p(n-m,m);
  
 }

主函数代码:

 public static void main(String[] args) {
  System.out.println("6的整数划分有"+p(6, 6)+"种");
  
 }

输出结果

在这里插入图片描述


  1. 用p(n-m,m)来表示是因为:划分中已经包含了m,所以只需要划分n-m的数据。例如,p(6-4,4)这个划分中第一个数为4,以4为划分第一个数继续划分。
    第二个参数有些玄学,个人理解不深:
    在比较 n-m和m的大小的时候,产生了一个很有意思的现象:
    当n-m>m的时候,由于我们要保证最大值是6,所以我们必须得给他的划分设置一个界限而这个界限的大小就是m
    当n-m<m的时候,我们不用考虑界限的选取,因为假如界限选的很大都会成为第一种情况而导致界限变成n-m ↩︎

猜你喜欢

转载自blog.csdn.net/vangoudan/article/details/106269793