题目描述:
将正整数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)。 )
代码实现:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 2e5+100;
int sol(int n,int m) {
//状态转移不是很明白怎么回事。。。
if(n==1||m==1)return 1;
else if(n<m)return sol(n,n);
else if(n==m)return 1+sol(n,m-1);
else return sol(n,m-1)+sol(n-m,m);
//1<m<n
}
int main() {
int n,m;
while(scanf("%d%d",&n,&m)!=EOF) {
printf("%d\n",sol(n,m));
}
return 0;
}
THE END;