【递归】 整数划分问题

资料主要来源于:
【计算机算法设计与分析(第五版)】【王晓东】【电子工业出版社】

例5 整数划分问题

将正整数n表示成一系列正整数之和:n=n1+n2+…+nk,其中n1≥n2≥…≥nk≥1,k≥1。
正整数n的这种表示称为正整数n的划分。求正整数n的不同划分个数。
例如:正整数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。

一些经典的递归问题(阶乘,斐波那契),问题本身都具有比较明显的递归关系,因而容易用递归函数直接求解。

在本例中,如果设p(n)为正整数n的划分数,则难以找到递归关系,因此考虑增加一个自变量:将最大加数n1不大于m的划分个数记作q(n,m)。可以建立q(n,m)的如下递归关系。(若不理解加粗部分,建议把题目多读几遍)

(1) q(n,1)=1, n≥1; 当最大加数n1不大于1时,任何正整数n只有一种划分形式, 即n=1+1+…+1(n个1)

(2) q(n,m)=q(n,n), m ≥ n;
最大加数n1实际上不能大于n。因此,q(1,m)=1。

(3) q(n,n)=1+q(n,n-1);
正整数n的划分由n1=n的划分和n1 ≤ n-1的划分组成。

(4) q(n,m)=q(n,m-1)+q(n-m,m), n>m> 1;
正整数n的最大加数n1不大于m的划分,由n1≤ m-1 的划分和n1=m的划分组成。n1=m 的划分就是该划分中必然包含数m,因此其划分的数目与n-m的m划分一致。

如果设p(n)为正整数n的划分数,则难以找到递归关系,因此考虑增加一个自变量:将最大加数n1不大于m的划分个数记作q(n,m)。可以建立q(n,m)的如下递归关系。(正整数n的划分数p(n)=q(n,n)。 )

【递归】 整数划分问题
q(n,m)=q(当前需要被划分的数字,划分中的加数的最大取值)

#include <iostream>
using namespace std;

int q(int n, int m)
{
    if((n < 1) || (m < 1)) //无意义情况 
        return 0;
    if((n == 1) || (m == 1))//数字1,划分最大加数为1的划分只会有1种 
        return 1;
    if(n < m)			   //需要划分的数字n,实际情况不会小于其划分最大加数 
        return q(n, n);
    if(n == m)				//正整数n的划分由n1=n的划分和n1 ≤ n-1的划分组成。 
        return q(n, m - 1) + 1;
    return q(n, m - 1) + q(n - m, m);//被划分数为n,最大划分加数为m的划分数目,等于, 
	// 被划分数为n最大加数为m-1的划分数目 + 被划分数为(n-m)最大加数为m的划分数目   
}

int	main()
{
    int	m = 6, n = 6;
    for(int i=1;i<=6;i++)
    {
    	cout <<"  数字为"<<n<<"时,最大划分加数上限为"<<i<<"时的划分情况有"<< q(n, i) <<"种"<< endl;
	}
    
}

【递归】 整数划分问题