整数划分是一个比较典型的递归问题:将一个整数
n
n
n 划分为值不超过
m
m
m 的一系列数的组合。
例如,若
n
=
5
n=5
n=5,
m
=
4
m=4
m=4, 则划分可以为:{4,1}, {3,1,1}, {3,2}, {2,1,1,1}, {2, 2, 1},{1,1,1,1,1}。共有 6 个组合。
记组合个数为
f
(
n
,
m
)
f(n,m)
f(n,m),则递归公式为:
f
(
n
,
m
)
=
{
f
(
n
,
m
−
1
)
+
f
(
n
−
m
,
m
)
n
>
m
>
1
1
+
f
(
n
,
m
−
1
)
n
=
m
>
1
f
(
n
,
n
)
m
>
n
>
1
1
n
=
1
or
m
=
1
f(n,m)=\begin{cases} f(n,m-1)+f(n-m,m)\quad &n>m>1\\ 1+f(n,m-1)\quad & n=m>1\\ f(n,n) & m>n>1\\ 1 &n=1\text{ or } m=1 \end{cases}
f(n,m)=⎩⎪⎪⎪⎨⎪⎪⎪⎧f(n,m−1)+f(n−m,m)1+f(n,m−1)f(n,n)1n>m>1n=m>1m>n>1n=1 or m=1
第一个等式分包不包含
m
m
m 两种情况。
若只要输出划分的总数,网上参考资料比较多,也比价容易理解。
若还要求把具体的划分结果输出,网上资料比较少,我自己从国外网站搜了下,找到了一个答案,同样利用到了递推思想,主要是:
java 代码:
/**
* @author chen zhen
* @version 创建时间:2018年4月25日 下午4:51:23
* @value 类说明: 整数划分,并输出结果
*/
public class IntegerPartion {
// 查询划分次数
static int countPartion(int n, int m) {
if (n ==1 || m == 1)
return 1;
else if (m > n)
return countPartion(n, n);
else if (m ==n )
return 1 + countPartion(n, n-1);
else if (m < n)
return countPartion(n-m, m) + countPartion(n, m-1);
return 0;
}
// 输出具体划分
static void countOutput(int n, int m, String str) {
if (n == 0) // 递归跳出条件1
System.out.println(str);
else {
if (m > 1) // 递归跳出条件2
countOutput(n, m-1, str);
if (m <= n) // 因为递归时可能出现 m>n 的情况
countOutput(n-m, m, m + " " + str);
}
}
public static void main(String[] args) {
int m = 5;
int n = 6;
System.out.println(countPartion(m, n));
countOutput(m, n, "");
}
}
Python 代码:
# 输出整数划分个数
def f1(n, m):
if n==0 or m ==0:
return 0
if n==1 or m ==1 :
return 1
if m == n:
return 1 + f1(n, n-1)
elif m > n:
return f1(n, n)
elif m < n:
return f1(n-m, m) + f1(n, m-1)
# 输出具体的整数划分
def f2(n, m, string):
if n == 0:
print(string)
else:
if m>1:
f2(n, m-1, string)
if m <= n:
f2(n-m, m, str(m)+ ' '+string)
n = 5; m = 4
print(f1(n, m))
f2(n, m, '')
输出结果:
6
1 1 1 1 1
1 1 1 2
1 2 2
1 1 3
2 3
1 4