整数的分划问题

[整数的分划问题]
  对于一个正整数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)。


分析:

从上面n=6的例子可以看出,很难找到大规模问题P(M)与小规模问题P(n-d)  (d=1,2,3...)的关系。

根据n=6可以发现:第一行及以后的数据不超过6,第二行及以后的数据不超过5,。。。第六行及以后的数据不超过1。


  解析:
  我们定义一个函数Q(n,m),表示整数n的“任何被加数都不超过m”的分划的数目。
  Q(n,m)有以下递归关系:
 (1)Q(n,n)=1+Q(n,n-1)

等式右边的1表示“n只包含一个被加数等于n本身的划分;则其余的分划表示n的所有其他划分,即最大加数m<=n-1的划分。

(2)Q(n,m)=Q(n,m-1)+Q(n-m,n)   (m<n)

等式右边的第一部分表示被加数中不包含m的分划的数目;第二部分表示被加数中包含(注意不是小于)m的分划的数目,因为如果确定了一个分划

的被加数中包含m,则剩下的部分就是对n-m进行不超过m的划分。


到此找到了大规模问题与小规模问题的递归关系,下面是递归的停止条件:

(1)Q(n,1)=1,表示当最大的被加数是1时,该整数n只有一种划分,即n个1相加;

(2)Q(1,m)=1,表示整数n=1只有一种划分,不管最大被加数的上限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的增加增长的非常快(以指数级增长),所以
  不要用较大的整数来测试按照上述算法编写出的程序。


代码如下:

#include <stdio.h>

int Divide(int n,int m);

int main()
{
	int n;
	scanf("%d",&n);
	printf("%d\n",Divide(n,n));

	return 0;
}

int Divide(int n,int m)
{
	if (n<1||m<1)
	{
		printf("Error\n");
	}
	else if (n==1||m==1)
	{
		return 1;
	}
	else if (n<m)
	{
		return Divide(n,n);
	}
	else if (n==m)
	{
		return 1+Divide(n,n-1);
	}
	else
	{
		return Divide(n,m-1)+Divide(n-m,m);
	}
}


你可能感兴趣的:(整数的分划问题)