把一个整数分成k份
division an integer into k parts
我正在 java 编程,我需要制定一个算法。算法的要求是:
- 我们有 3 个整数变量
n
、m
、k
;
- 我们想将
n
分成 k
个部分,这样 k
个部分的总和
等于n
,每个部分都是1
和m
之间的整数。
- 我们需要所有可能的整数组合。
例如输入集:
n = 7; m = 3; k = 4
我们可以制定两种不同的组合:
7 = 2 + 2 + 2 + 1
和
7 = 3 + 2 + 1 + 1
谢谢大家
要获得 "number of divisions" 的计数,您可以使用 Dynamic Programming,它遵循递归公式:
D(0,0,j) = 1
D(x,0,j) = 0 x > 0
D(x,i,j) = 0 x < 0 or j<0
D(x,i,j) = D(x-j,i-1,j) + D(x,i,j-1)
D(n,k,m)
表示的答案就是这样划分的次数。
复杂度为O(n*k*m)
Java代码:
public static int numDivisions(int n, int m, int k) {
int[][][] D = new int[n+1][k+1][m];
for (int j = 0; j < m; j++) {
for (int x = 0; x <= n; x++) {
D[x][0][j] = 0;
}
D[0][0][j] = 1;
}
for (int i = 1; i <= k; i++) {
for (int x = 0; x <= n; x++) {
for (int j = 0; j < m; j++) {
D[x][i][j] = 0;
if (j > 0) D[x][i][j] += D[x][i][j-1];
if (x-j-1 >=0) D[x][i][j] += D[x-j-1][i-1][j];
}
}
}
return D[n][k][m-1];
}
附带说明一下,这类似于 stars and bars 问题 - 但这里的顺序无关紧要,此外,单元格中 "stars" 的数量有上限。
我相信这可以通过递归轻松完成。首先检查你是否可以划分n
,即n<=m*k && n>=k
,如果不能,return空数组。
如果可整除,依次从范围[1..m]
中选择m'
作为第一个数字,然后递归得到其余的参数n'=n-'m, m'=m', k'=k-1
,然后return所有的结果。
只有 n=0
和 k=0
的递归才会成功停止。时间复杂度应该和输出的大小一样。
这个想法是一种回溯算法方法(递归),您可以减少参数并获得部分解决方案,然后检查您是否有正确的解决方案。
public class Problem {
private static void algorithm(int n, int k, int m) {
algorithmRecursive(Collections.EMPTY_LIST, n, k, m, 1);
}
private static void algorithmRecursive(List<Integer> partial, int n, int k, int m, int min) {
if ( (k > 0) ) {
// Optimization
if ((n <= k * m) && (n >= k*min)){
for (int i = min; i <= Math.min(m, n); i++) {
List<Integer> newPartial = new ArrayList<>(partial);
newPartial.add(i);
algorithmRecursive(newPartial, n - i, k - 1, m, i);
}
}
} else if (n == 0) {
// Right solution
System.out.println(partial);
}
}
public static void main(String[] args) {
algorithm(7,4,3);
}
}
我正在 java 编程,我需要制定一个算法。算法的要求是:
- 我们有 3 个整数变量
n
、m
、k
; - 我们想将
n
分成k
个部分,这样k
个部分的总和 等于n
,每个部分都是1
和m
之间的整数。 - 我们需要所有可能的整数组合。
例如输入集:
n = 7; m = 3; k = 4
我们可以制定两种不同的组合:
7 = 2 + 2 + 2 + 1
和
7 = 3 + 2 + 1 + 1
谢谢大家
要获得 "number of divisions" 的计数,您可以使用 Dynamic Programming,它遵循递归公式:
D(0,0,j) = 1
D(x,0,j) = 0 x > 0
D(x,i,j) = 0 x < 0 or j<0
D(x,i,j) = D(x-j,i-1,j) + D(x,i,j-1)
D(n,k,m)
表示的答案就是这样划分的次数。
复杂度为O(n*k*m)
Java代码:
public static int numDivisions(int n, int m, int k) {
int[][][] D = new int[n+1][k+1][m];
for (int j = 0; j < m; j++) {
for (int x = 0; x <= n; x++) {
D[x][0][j] = 0;
}
D[0][0][j] = 1;
}
for (int i = 1; i <= k; i++) {
for (int x = 0; x <= n; x++) {
for (int j = 0; j < m; j++) {
D[x][i][j] = 0;
if (j > 0) D[x][i][j] += D[x][i][j-1];
if (x-j-1 >=0) D[x][i][j] += D[x-j-1][i-1][j];
}
}
}
return D[n][k][m-1];
}
附带说明一下,这类似于 stars and bars 问题 - 但这里的顺序无关紧要,此外,单元格中 "stars" 的数量有上限。
我相信这可以通过递归轻松完成。首先检查你是否可以划分n
,即n<=m*k && n>=k
,如果不能,return空数组。
如果可整除,依次从范围[1..m]
中选择m'
作为第一个数字,然后递归得到其余的参数n'=n-'m, m'=m', k'=k-1
,然后return所有的结果。
只有 n=0
和 k=0
的递归才会成功停止。时间复杂度应该和输出的大小一样。
这个想法是一种回溯算法方法(递归),您可以减少参数并获得部分解决方案,然后检查您是否有正确的解决方案。
public class Problem {
private static void algorithm(int n, int k, int m) {
algorithmRecursive(Collections.EMPTY_LIST, n, k, m, 1);
}
private static void algorithmRecursive(List<Integer> partial, int n, int k, int m, int min) {
if ( (k > 0) ) {
// Optimization
if ((n <= k * m) && (n >= k*min)){
for (int i = min; i <= Math.min(m, n); i++) {
List<Integer> newPartial = new ArrayList<>(partial);
newPartial.add(i);
algorithmRecursive(newPartial, n - i, k - 1, m, i);
}
}
} else if (n == 0) {
// Right solution
System.out.println(partial);
}
}
public static void main(String[] args) {
algorithm(7,4,3);
}
}