简单整数划分与放苹果问题思考(递归)

这两个问题几乎是相同的,但是以放苹果的方式来思考问题明显会更易理解。下面先看一下两个问题的描述。

整数划分

描述
将正整数n 表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。
正整数n 的这种表示称为正整数n 的划分。正整数n 的不同的划分个数称为正整数n 的划分数。

分苹果问题

M个同样的苹果放N个同样的盘子,允许有盘子空着, 问有多少种放法。注意:5 1 1和1 5 1是同一种放法

一、问题分析

定义函数f(m,n)。
对于整数划分: m是要划分的整数,n是划分里可能最大的数(不一定会有n);
对于放苹果: m要放的苹果总数,n是盘子个数。

以下为可能出现的m、n情况:
(1)m=1,或n=1,f(m,n)=1。在整数划分里,数字1显然只有一种划分方法,数m的最大划分为1时也只有一种情况(m个1);分苹果里,一个苹果只有一种方法(不区分盘子),一个盘子也只能把所有苹果都放进来这一个结果。
(2)m<1,或n<1,f(m,n)=0。整数划分里,要求数为正数,所以小于1无法进行划分,划分方式为0。当没有苹果或者没有盘子时,也是无法“放苹果的”。
(3)m<n,f(m,n)= f(m,m)。被划分的数为m,当然划分里最大的的数也只能是m了;苹果只有m个,最多放到m个盘子里。
(4)m=n,f(m,n)= 1+f(m,m-1)
数m的最大划分为m的情况=包含m的划分(m自身)+不包含m的划分(最大只能为m-1);m个苹果放到m个盘子里=第m个盘子放苹果+第m个盘子不放苹果;
(5)m>n,f(m,n)= f(m-n,n)+f(m,n-1)。如果理解了第4条,就好理解很多。

对于放苹果,把m个苹果放到n个盘子里=n个盘子都不为空+至少有一个为空。而要实现n个盘子都不为空,可以先把n个盘子里各放一个苹果,还剩m-n个苹果随机放,即为f(m-n,n)。至少有一个为空也等于最多n-1个盘子放苹果,f(m,n-1)。

对于整数划分,还是比较抽象的。
数m的划分最大可能为n=数m划分里一定包含n+数m的划分里一定不含n(最大就为n-1)
怎么实现一定包含n呢?那我们就先从整数m里分一个n出来呗,易有m-n=m-n(哈哈,假装算一下),这就保证了一定含n,剩下的数为m-n再随机划分为f(m-n,n),不需要考虑m-n和n的相对大小(递归哦,我们3,4,5就是干这个的)。
一定不含n就简单了吧,那就让最大的可能变为n-1啊,f(m,n-1)。

个人感觉整数划分和放苹果的理解难度相差太大,当初整数划分困惑了我很久,尤其是第5点,直到苹果砸了一下我的脑袋。

建议从放苹果的角度理解

(哦,在放苹果问题里,有的是认为没有苹果的时候,结果就为1,个人理解起来很困惑,而且按照那样的思路理解好了后,遇到整数问题就得换思路了。)

二、源代码



#include <iostream>
using namespace std;

int f(int m, int n);

int main()
{
	int num;
	while (cin>>num)
	{
		cout << f(num, num) << endl;
	}
		
	return 0;
}

int f(int m, int n)//m为苹果个数,n为盘子个数
{
	if (n == 1 || m == 1) return 1;
	if (n <1 || m < 1) return 0;
	if (n == m) return 1 + f(m, m - 1);
	if (n > m) return f(m, m);
	if (n < m) return f(m - n, n) + f(m, n - 1);
}

发布了13 篇原创文章 · 获赞 7 · 访问量 595

猜你喜欢

转载自blog.csdn.net/hejnhong/article/details/104566317