我想计算N个整数的不同有序组的数量,以便每个组的元素总和为A
例如:如果N = 3且A = 3,则结果应为10:
1 = [3,0,0]
2 = [2,1,0]
3 = [1,2,0]
4 = [0,3,0]
5 = [2,0,1]
6 = [1,1,1]
7 = [0,2,1]
8 = [1,0,2]
9 = [0,1,2]
10 = [0,0,3]
我这样做的方式是蛮力:
public static int calc(int a, int n){
if (n <= 1 || a == 0) return 1;
int sum = 0;
for (int i=0; i<=n; i++)
sum += calc(a - i, n - 1);
return sum;
}
我怀疑可能有更好的方法(我错过了一些数学计算......) 在那里?
修改 在原始问题中,我忘了考虑订单
答案 0 :(得分:5)
答案 1 :(得分:3)
想象一下长度A
的大段。并设想N-1
有序分隔符,将分段划分为多个部分。因此,每个部分都是一个加数,而整个部分是一个总和。
Ergo,您只需要提供枚举分隔符位置的算法。
您可以放入任何N+1
个位置的第一个分隔符P_0 = {0,1,... N}
第二个分隔符可以进入P_1 = {P_0,... N}
中的任何一个等等。
您可以使用递归来实现此目的。
答案 2 :(得分:2)
我确信有一个数学计算来回答这个问题,但由于这是一个编程Q&amp; A,我会告诉你如何让你的程序更快地给出答案:你可以使用memoization。< / p>
目前,您的计划每次都会重新计算calc(a, n)
的答案。但是,答案可以计算一次,因为它在后续调用中不会更改。为calc(a,n)
的结果添加一个2D数组,用-1
初始化,并在计算结果之前使用它来查找结果,以节省大量时间反复重复计算相同的数字:
private static int[][] memo = new int[30][30];
static {
for(int i = 0 ; i != 30 ; i++)
for(int j = 0 ; j != 30 ; j++)
memo[i][j] = -1;
}
public static int calc(int a, int n){
if (n <= 1 || a == 0) return 1;
if (memo[a][n] > 0) return memo[a][n];
int sum = 0;
for (int i=0; i<=n; i++)
sum += calc(a - i, n - 1);
return (memo[a][n] = sum);
}
答案 3 :(得分:1)
对于枚举:使用上面其他解决方案中给出的公式,效率更高。除非需要,否则您永远不想实际生成一整套n整数合成。它们具有难以处理的属性,特别是如果您只想要总计它们,而不是生成它们。生成它们是另一个问题......
用于生成:使用无环路算法...有很多O(1) - 灰色代码序列结果。限制整数组合的变化非常少,没有或没有无循环算法。在整类组合的这类问题中有许多算法,其中大多数是非常具体的,但是对于这个特定问题存在大量现代无循环算法。超级高效。除非你有大量的并行计算功能,否则蛮力绝不是解决这个问题的方法。 Google或Google Scholar随时为您服务! :d
希望这有帮助!
答案 4 :(得分:0)
我找到了另一个解决方案,只是递归而没有分隔符:
public class App201210121604 {
public static Vector<int[]> split(int sum, int count) {
if( sum < 0 ) {
throw new IllegalArgumentException("Negative sum is not allowed");
}
Vector<int[]> ans = new Vector<int[]>();
// "reserved" end of recursion
if( count <= 0 ) {
// nothing to do
}
// end of recursion
else if( count == 1 ) {
ans.add(new int[] {sum});
}
// body of recursion
else {
// for each first summand from 0 to summ
for(int i=0; i<=sum; ++i) {
// do a recursion to get the "tail"
for(int[] tail : split(sum-i, count-1)) {
int[] group = new int[count];
group[0] = i;
System.arraycopy(tail, 0, group, 1, count-1);
ans.add(group);
}
}
}
return ans;
}
public static void main(String[] args) {
Vector<int[]> ans = split(8, 4);
for(int[] group : ans) {
for(int i=0; i<group.length; ++i) {
if( i>0 ) System.out.print("+");
System.out.print(group[i]);
}
System.out.println("");
}
}
}