您的位置:首页 > 编程语言 > Java开发

整数划分问题(Java版)

2015-03-28 18:18 225 查看
整数划分问题:将正整数n表示成一系列正整数之和:,其中,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}。

对于任意的正整数n,可以表示为一些整数相加的形式,我们可以把n的划分函数p(n)定义为另一种形式q(n,m)。其中,n表示那些相加的整数中最大的那一个加数,m表示那些相加的整数一定不能够大于m。那么对于一个函数q(n,m),我们可以分成4种情况来讨论:

情况一:当n = = 1 || m = = 1时,返回的是1。这里可以分成两个小部分来看,当n = = 1时,也就是说最大加数为1,自然只有一种情况,当m = = 1时,那么相加每一个整数都不能大于1,那么也只有全部都是1这一种情况。

情况二:当n = = m时,返回的是1+q(n,n-1)。也就是说n的加数就是n(因为n= =m),那么这个时候就增加了一种划分情况,就是n={n},但是只是返回1是不够的,因为函数q(n,m)本身的功能是计算最大加数n不大于m的划分个数,所以还要进一步递归计算整数n不大于n-1的划分数,也就是q(n,m)。这种情况也是算法第一次被执行就触发的情况,因为算法一开始是求n的所有划分情况,那么一开始传入的参数为q(n,n),首先第一种情况为n的加数是n,那么还要继续求q(n,n-1),所以当n = = m时,return 1+q(n,n-1)。

情况三:当n < m 时,返回的是q(n,n)。我们再一次强调一下q(n,m)这个函数的功能时计算最大加数n不大于m的划分个数,如果n < m的时候,这和函数的功能时矛盾的,不过m其实可以缩小范围,缩小到n,这时只需要计算最大加数n不大于n的划分个数即可。

情况四:当n > m > 1时,返回的是q(n,m-1) + q(n-m,m)。在这个条件下,最大加数n不能大于m,所以最大加数是m,那么只需要算最大加数为n-m不大于m的划分个数就行了,即q(n-m,m),要注意的是条件是不大于m,因为当前函数已经说明了最大加数不能够大于m了,那么递归的下一层函数也要不大于m,比如说:在算6的所有划分数时,只能够出现6=3+2+1,不能够出现6=2+3+1这种情况,因为第一个加数已经确定是2的话,第二个加数就一定要小于2。

在分析完这4中情况之后,给出下面的递归表达式:

为了测试算法的正确性,我们带入题目给出的求正整数6划分个数来验证。一开始划分数为0。正整数6可以由一些加数通过加法相加来得到,为了方便分析,先把这些加数的集合定义为A。

第一步:带入q(6,6),进入函数之后,符合n = = m这中情况,那么此时首先是增加了第一种情况,就是集合A中最大的加数为6的时候,只有一种情况,即6 = {6},在划分数加1之后,继续递归计算集合A中最大加数为5的所有划分个数,也就是q(6,5)。所以当n = = m时,公式:q(n,m) = 1 + q(n, n-1)是正确的。

第二步:这一步计算的是q(6,5),符合第四种情况(n>m>1)。当集合A中最大加数已经确定是5之后,那么只需要计算6-5=1不大于5的所有划分数就是整数6的所有以5开头的加法因子的划分数,也就是q(1,5)。在计算最大加数为5的划分数之后,还需要继续递归计算最大加数为4的划分数,也就是q(6,4)。所以当n>m>1时,公式q(n,m) = q(n,m-1) + q(n-m,m)是正确的。

第三步:因为上一步有两个递归公式,首先先考虑q(n-m,m)也就是q(1,5),当最大加数为1的时候,由情况一可以知道只有加数是1这一种情况,在这里就可以确定集合A中一最大加数为5开头的所有划分情况只有一种,就是6={5+1}。这里有根据公式q(n,m) = q(n,m-1) + q(n-m,m)接着把q(6,4)划分为q(6,3)+q(6-4,2)。

后面的情况几乎和前面3步分析的情况差不多。所以我们可以根据上面的递归公式来计算出任意一个正整数的所有划分数。但是题目还需要打印所有划分的情况,那么我们可以定义一个全局数组变量int a[],来记录每一个加数,所以我们可以把上述所说的递归方程q(n,m)改成q(n,m,i),这里的i表示数组a的下标,那么在每一次递归方法中,第一个操作就是赋值给数组,也就是执行操作a[i]=m。

import java.util.Scanner;

public class Lab1_2 {
static int[] a = new int[1000];

public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
while(in.hasNextInt()) {
int n = in.nextInt();
int count = q(n, n, 0);
System.out.println(count);
}
}

public static int q(int n, int m, int i) {
if(n < m) {
return q(n, n, i);
}
a[i] = m;
if(n == 0 || m == 0) {
//打印下标从0到i
printPartition(i);
return 0;
}
if(n == 1 || m == 1) {
if(n == 1) {
//打印下标从0到i
printPartition(i);
}
else q(n-1, 1, i+1);
return 1;
}
if(n == m) {
//打印下标从0到i
printPartition(i);
return 1 + q(n, n-1, i);
}

return q(n-m, m, i+1) + q(n, m-1, i);
}

public static void printPartition(int i) {
System.out.print("{");
for(int j = 0; j <= i; j++) {
if(j == i) System.out.print(a[j]);
else System.out.print(a[j] + "+");
}
System.out.println("}");
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: