问题描述
我要解决以下问题:给定数字N和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的一部分,也可能不是,所以我们需要计算这两种可能性。
注意::对于任何i,f(i,0)= 1,这意味着您可以通过一种方式获得和= 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];