[整数的分划问题]
对于一个正整数M的分划就是把M写成一系列正整数之和的表达式。例如,对于正整
数M=6,它可以分划为:
6
5+1
4+2, 4+1+1
3+3, 3+2+1, 3+1+1+1
2+2, 2+2+1+1, 2+1+1+1+1
1+1+1+1+1+1
注意,分划与顺序无关,例如5+1和1+5是同一种分划。另外,这个整数M本身也算
是一种分划。现在的问题是,对于给定的正整数M,要求编程序计算出其分划的数
目P(M)。
解析:
我们定义一个函数Q(M.N),表示整数M的“任何被加数都不超过N”的分划的数目。
Q(M.N)有以下递归关系:
1)Q(M,1)=1,表示当最大的被加数是1时,该整数M只有一种分划,即M个1相加;
2)Q(1,N)=1,表示整数M=1只有一个分划,不管最大被加数的上限N是多大;
3)Q(M,N)=Q(M,M),如果M<N。很明显,M的分划不可能包含大于M的被加数N;
4)Q(M,M)=1+Q(M,M-1)。等式的右边分为两部分:第一部分的1表示M只包含一个被
加数等于M本身的分划;第二部分表示M的所有其他分划的最大被加数N<=M-1,所以
其他分划的数目就是等式右边的第二项。
5)Q(M,N)=Q(M,N-1)+Q(M-N,N),如果M>N。等式右边的第一部分表示被加数中不包
含N的分划的数目;第二部分表示被加数中包含N的分划的数目,因为如果确定了一
个分划的被加数中包含N,则剩下的部分可以按照对M-N的分划进行划分。
上述五个递归关系式对Q(M,N)作了递归定义。因为M的所有分划的数目P(M)=Q(M,
M),所以上述关系式也定义了P(M)。
有了递归关系式后,解决问题的算法就非常简单了:
Partition(M, N)
1. if M < 1 or N < 1
2. then Error("输入参数错误")
3. else if M = 1 or N = 1
4. then return 1
5. else if M < N
6. then return Partition(M, M)
7. else if M = N
8. then return (1 + Partition(M, M-1))
9. else
10. return (Partition(M, N-1) + Partition(M-N, N));
请注意,正整数的划分的数目随着M的增加增长的非常快(以指数级增长),所以
不要用较大的整数来测试按照上述算法编写出的程序。
想法二:
求正整数n的不同划分个数,将最大数n1不大m的划分记住做q(n,m),叫做n的m划分。
输入:n m
输出:n的m划分的总个数。
我的思路:首先要找出递归的公式来,首先分析几种简单的情况,n==1||m==1可以直接得出结果为1;而当n<m时,可以直接求出q(n,n);当n=m时,因为对于n本身只有一种情况,即n,所有可以直接用1+q(n,n-1)来求。最后当n>m时,可以用q(n,m-1)+q(n-m,m),其中q(n-m,m表示的时当m固定后,求剩下可能的情况。参考下图:
代码:
//求整数划分的个数
#include <stdio.h>
int Divid(int n, int m)
{
if (n == 1 || m == 1) return 1; //必须是或
if (n < m) return Divid(n,n);
if (n == m) return 1 + Divid(n,n-1);
return Divid(n,m-1) + Divid(n-m,m);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
printf("%d\n",Divid(n,m));
return 0;
}