使用 (1,...,K) 找出加到 N 上的可能总和数
Find the number of possible sums which add to N using (1,...,K)
我有以下问题要解决:给定一个数 N 和 1<=k<=N,计算 (1,...,k) 与 N 相加的可能和数。可能有相等的因子(例如,如果 N=3 和 k=2,(1,1,1) 是一个有效的总和),但是 不能计算排列(例如,如果 N=3 和k=2,将 (1,2) 和 (2,1) 算作一个解)。我已经实现了下面的递归 Python 代码,但我想找到一个更好的解决方案(也许使用动态编程?)。它看起来类似于 triple step problem,但具有不计算排列的额外限制。
def find_num_sums_aux(n, min_k, max_k):
# base case
if n == 0:
return 1
count = 0
# due to lower bound min_k, we evaluate only ordered solutions and prevent permutations
for i in range(min_k, max_k+1):
if n-i>=0:
count += find_num_sums_aux(n-i, i, max_k)
return count
def find_num_sums(n, k):
count = find_num_sums_aux(n,1,k)
return count
这是动态规划中的标准问题(子集和问题)。
让我们定义函数 f(i,j),它给出了使用数字子集 (1...i) 获得和 j 的方法的数量,那么您的问题的结果将是 f (k,n).
对于范围 (1...i) 中的每个数字 x,x 可能是总和 j 的一部分,也可能不是,所以我们需要计算这两种可能性。
注意: f(i,0) = 1 for any i,这意味着你可以通过一种方式得到 sum = 0 这种方式是不采取任何范围 (1...i).
中的数字
这是用 C++ 编写的代码:
int n = 10;
int k = 7;
int f[8][11];
//initializing the array with zeroes
for (int i = 0; i <= k; i++)
for (int j = 0; j <= n; j++)
f[i][j] = 0;
f[0][0] = 1;
for (int i = 1; i <= k; i++) {
for (int j = 0; j <= n; j++) {
if (j == 0)
f[i][j] = 1;
else {
f[i][j] = f[i - 1][j];//without adding i to the sum j
if (j - i >= 0)
f[i][j] = f[i][j] + f[i - 1][j - i];//adding i to the sum j
}
}
}
cout << f[k][n] << endl;//print f(k,n)
更新
要处理我们可以重复元素的情况,例如 (1,1,1) 将得到总和 3,您只需要通过更改以下代码行允许多次选取相同的元素:
f[i][j] = f[i][j] + f[i - 1][j - i];//adding i to the sum
为此:
f[i][j] = f[i][j] + f[i][j - i];
我有以下问题要解决:给定一个数 N 和 1<=k<=N,计算 (1,...,k) 与 N 相加的可能和数。可能有相等的因子(例如,如果 N=3 和 k=2,(1,1,1) 是一个有效的总和),但是 不能计算排列(例如,如果 N=3 和k=2,将 (1,2) 和 (2,1) 算作一个解)。我已经实现了下面的递归 Python 代码,但我想找到一个更好的解决方案(也许使用动态编程?)。它看起来类似于 triple step problem,但具有不计算排列的额外限制。
def find_num_sums_aux(n, min_k, max_k):
# base case
if n == 0:
return 1
count = 0
# due to lower bound min_k, we evaluate only ordered solutions and prevent permutations
for i in range(min_k, max_k+1):
if n-i>=0:
count += find_num_sums_aux(n-i, i, max_k)
return count
def find_num_sums(n, k):
count = find_num_sums_aux(n,1,k)
return count
这是动态规划中的标准问题(子集和问题)。
让我们定义函数 f(i,j),它给出了使用数字子集 (1...i) 获得和 j 的方法的数量,那么您的问题的结果将是 f (k,n).
对于范围 (1...i) 中的每个数字 x,x 可能是总和 j 的一部分,也可能不是,所以我们需要计算这两种可能性。
注意: f(i,0) = 1 for any i,这意味着你可以通过一种方式得到 sum = 0 这种方式是不采取任何范围 (1...i).
这是用 C++ 编写的代码:
int n = 10;
int k = 7;
int f[8][11];
//initializing the array with zeroes
for (int i = 0; i <= k; i++)
for (int j = 0; j <= n; j++)
f[i][j] = 0;
f[0][0] = 1;
for (int i = 1; i <= k; i++) {
for (int j = 0; j <= n; j++) {
if (j == 0)
f[i][j] = 1;
else {
f[i][j] = f[i - 1][j];//without adding i to the sum j
if (j - i >= 0)
f[i][j] = f[i][j] + f[i - 1][j - i];//adding i to the sum j
}
}
}
cout << f[k][n] << endl;//print f(k,n)
更新
要处理我们可以重复元素的情况,例如 (1,1,1) 将得到总和 3,您只需要通过更改以下代码行允许多次选取相同的元素:
f[i][j] = f[i][j] + f[i - 1][j - i];//adding i to the sum
为此:
f[i][j] = f[i][j] + f[i][j - i];