使用1,...,K找出加到N的可能和的数量

问题描述

我要解决以下问题:给定数字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];