经典递归问题-整数划分问题

“经典”一词只是对我这个小白而言,相比于另一个经典递归问题-汉诺塔,我认为这个问题理解起来也更难一些(其实汉诺塔当初我也不咋会写,在b站看了几个视频才有的头绪),下面,我们来看一下整数划分问题

题目
将一个正整数n表示成一系列正整数之和,n=n1+n2+…+nk,其中n1≥n2≥…≥nk≥ 1,k ≥1
正整数n的一个这种表示称为正整数n的一个划分。正整数n的不同划分个数称为正整数n的划分数,记做p(n)。
如正整数6有如下11种不同的划分,所以p(6)=11。
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;

我先检讨一下我们问题吧,刚看到这个题,感觉挺简单的,以至于题目中要求一个划分必须是一个非增序列我都没看到,其次呢,对于这个题,我感觉递归出口应该是当n=1时,返回1就可以了,递归函数呢,比如求p(6)的话,应该是在p(5)的基础上加一些个条件啥的,显然,最后一定不对。

也百度了一下,CSDN也看了许多,大多数都是上来直接说递归公式,然后再给与一些说明啥的,跟着讲解,我也写了下来,但是我觉得这样会使你自己觉得已经懂了,但停个几天之后,同样的题目,你不再是思考这道题,而是去回忆你之前怎么做的,说的直白一点,就是背答案罢了。

接下来看这道题,我觉得这种思维挺难的,难在哪儿呢?这道题将p(n)进行了一个转化,转化为一个q(n,m),转化后的这个式子的意思是:对正整数n进行一个划分,划分中的最大数值不超过m,举个例子,q(6,4),表示为对6进行划分,最大数值不能超过4,这个m具体啥含义呢?我们看题目,划分序列要求是一个非增的序列,那么,n1在一般情况下是不是可以理解为整个序列的最大值呢?我觉得是可以的,以上我感觉就是最难的部分,特别是公式转化那一块。

有个q(n,m)这个公式,我们继续分析,由易到难,首先我要说的是,假如要求p(6),实则求q(6,6),这个应该没问题吧?对6的划分,不就是对6的划分中,最大值只能是6么?,题目规定ni不能是0或者负数。
第二点:q(n,m),当m>n时,它其实等价于q(n,n),举个例子,q(4,6),求4的划分,最大值不能超过6,题目规定,题目规定ni不能是0或者负数,其实在这,我们可以多想一下,与其说划分序列的各项ki不大于m,一般情况下,这不主要就是对k1而言么?
第三点:举一般的例子来说,q(n,m),它其实包含两种情况,一个种,k1等于m,第二种k1不等于m,转化一下,即k1<=m-1,这两种情况得多想想,懂了之后我们继续,对于第一种情况,当k1等于m时,我们会得到这样一个十字,n=m+k2+k3+…kn,移项后得到n-m=k2+k3+…kn,有没有感觉像是一个递归式?q(n-m,m);第二种情况:k1不等于m,即k1<=m-1,那么他是不是就等于q(n,m-1);综上,我们可以得到q(n,m)=q(n-m,m)+q(n,m-1);
第四点:上面的第二点主要说的是m>n的情况,第三点主要说的是一般情况下的m<n的情况,不难想到第三种情况,m=n,这是q(n,n)等于多少呢?我们举个例子说一下,q(6,6),它的最大划分是6,当划分是6时,它就已经属于一种划分了,所有,q(6,6)=q(6,5)+1;推广到一般的情况q(n,n)=q(n,n-1)+1;
第五点:就简单了,我们开始考虑递归出口,想到不想你会想到这么一条,q(n,1)=1,举个例子:q(6,1),因为最大值只能是1,所以这个划分只能是1,1,1,1,1,1 ,接下来就是一个错误的情况了,比如m<=0呀,n<=0呀,这些我们返回0就可以了,小面我们用代码来实现以下

#include <iostream>
using namespace std;
//m为n划分的子树中最大的整数 
int recursion(int n,int m){
 if(n<=0 || m<=0 ) return 0;
 if(m==1) return 1;
 if(m>n) return recursion(n,n);
 if(m==n) return 1+recursion(n,n-1);
 if(m<n) return recursion(n-m,m)+recursion(n,m-1);
}
int main(int argc, char** argv) {
 int n;
 cin>>n;
 cout<<recursion(n,n)<<endl;
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只学弱狗!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值