![](/img/trans.png)
[英]Find the number of ways to represent n as a sum of two integers with boundaries
[英]number of different groups of N integers that sum up to A
我想计算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;
}
我怀疑可能有更好的方法(我错过了一些数学计算......)吗?
编辑在原始问题中,我忘了考虑订单
想象一下长度为A
大段。 并想象N-1
有序分隔符,将分段分成几部分。 因此,每个部分是一个加数,而整个部分是一个总和。
因此,您只需提供算法来枚举分隔符位置。
可以放入N+1
位置的第一个分隔符P_0 = {0,1,... N}
第二个分隔符可以进入P_1 = {P_0,... N}中的任何一个
等等。
您可以使用递归来实现此功能。
我确信有一个数学计算来回答这个问题,但由于这是一个编程问答,我会告诉你如何让你的程序更快地给出答案:你可以使用memoization 。
目前,您的程序每次都会重新计算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);
}
对于枚举:使用上面其他解决方案中给出的公式,更加高效。 除非需要,否则您永远不想实际生成一整套n整数合成。 它们具有难以处理的属性,特别是如果您只想要总计它们,而不是生成它们。 生成它们是另一个问题......
用于生成:使用无环算法...有很多O(1) - 灰色代码序列结果。 限制整数组合的变化非常少,没有或没有无循环算法。 在整类组合的这类问题中有许多算法,其中大多数是非常具体的,但是对于这个特定问题存在大量现代无循环算法。 超级高效。 除非你有大量的并行计算功能,否则蛮力绝不是解决这个问题的方法。 Google或Google Scholar随时为您服务! :d
希望这可以帮助!
我找到了另一个解决方案,只是递归和没有分隔符:
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("");
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.