將N表示為K個非零整數之和的不同方法
問題“將N表示為K個非零整數之和的不同方法”在現實世界中有很多應用案例。
密碼學 − 在密碼學中,特定的加密方法是利用將數字N編碼為K個非零整數之和的概念設計的。
將整數N表示為K個非零整數之和,在最佳化方法的背景下,可能作為不同最佳化問題的子問題出現。
機器學習 − 在機器學習中,可以透過使用將整數N表示為K個非零整數之和的問題來建立描述資料點分佈的特徵向量。
解釋
現在讓我們解碼這個問題。
假設,我們給定兩個正整數N和K,我們需要找到K個非零整數,它們的和等於N。例如,如果N=10且K=3,我們需要找到三個非零整數,它們的和等於10。在這種情況下,一些可能的解是 −
1 + 4 + 5 2 + 3 + 5 2 + 4 + 4
請注意,在這些解的每一箇中,我們都有K=3個非零整數加起來等於N=10。
有不同的方法可以解決這個問題,讓我們討論每一種方法。
遞迴方法
使用遞迴方法查詢將N表示為K個非零整數之和的不同方法的分步演算法。
在主函式中輸入N和K的值。
建立函式f(N, K),它返回N可以表示為K個非零整數之和的總方法數。
如果N大於0,則返回1;否則,如果K = 1,則返回0。(基本情況)。
如果N == 0或K > N,則返回0。(基本情況)。
建立一個變數count來儲存結果。
將變數count的值設定為0。
對於每個整數I,從1到min(N-K+1, N-1)
遞迴計算f(N-i, K-1)。
將結果新增到count中。
返回count。
示例
上述演算法的實現
#include <iostream> using namespace std; int f(int N, int K) { if (K == 1) { return (N > 0) ? 1 : 0; // base case } if (N <= 0 || K > N) { return 0; // base case } int count = 0; for (int i = 1; i <= min(N-K+1, N-1); i++) { count += f(N-i, K-1); } return count; } int main() { int N = 5, K = 2; int ways = f(N, K); cout << "Number of ways to represent " << N << " as the sum of " << K << " non-zero integers: " << ways << endl; return 0; }
輸出
Number of ways to represent 5 as the sum of 2 non-zero integers: 4
複雜度
時間複雜度:O(N ^ K)。
空間複雜度:O(K)
二項式係數公式
可以使用星號和條形圖組合方法來獲得將正整數N表示為K個非零整數之和的方法數的公式。
想象一行N個星號(*),代表給定整數的N個分割槽單元。可以使用K-1個豎線(|), 將星號行分成K個段,來表示分割槽的K個非零整數。
例如,將10分成3個非零整數。可以使用下面的星號和豎線行來表示 −
* * | * * * | * * * * *
此圖的第一個部分表示數字2,第二個部分表示數字3,第三個部分表示數字5。
因此,將K-1個豎線排列在N個星號行中的方法數等於將N表示為K個非零整數之和的方法數。為此,我們使用公式:$\mathrm{C(N\:+\:K\:-\:1,\:K\:-\:1)}$。
根據二項式係數公式,$\mathrm{C(n,k)\:=\:n!\:/(k!*(n-k)!)}$。
但在我們的例子中,我們需要排除包含0的可能性。為了排除包含0作為其中一個加數的分割槽,我們可以使用以下方法 −
從N中減去1得到N-1。
將N-1分成K-1個非負整數。
將步驟2中獲得的K-1個非負整數中的每一個加1,得到K個非零整數,它們的和為N。
這種方法之所以有效,是因為每個加數的最小可能值是1(因為我們想要非零整數),因此我們從N中減去1以確保有足夠的單元剩餘分配給K個加數。
因此,我們得到公式:ways = C(N-1, K-1)
假設我們想找到將6表示為4個非零整數之和的方法數。我們可以使用前面推匯出的公式,即 −
C(N-1, K-1) = C(6-1, 4-1) = C(5, 3) = 10
這告訴我們,將6分成4個非零整數有10種方法。
它們是 −
1 + 1 + 1 + 3
1 + 1 + 2 + 2
1 + 1 + 3 + 1
1 + 2 + 1 + 2
1 + 2 + 2 + 1
1 + 3 + 1 + 1
2 + 1 + 1 + 2
2 + 1 + 2 + 1
2 + 2 + 1 + 1
3 + 1 + 1 + 1
方法
讓我們討論一下實現上述方法的分步演算法 −
在主函式中輸入N和K的值。
使用上述公式計算方法數。
列印ways的值。
現在讓我們編寫一些程式碼。
示例
使用二項式係數方法的程式碼實現
#include <iostream> using namespace std; int binomial(int n, int k) { int res = 1; if (k > n - k) { k = n - k; } for (int i = 0; i < k; ++i) { res *= (n - i); res /= (i + 1); } return res; } int main() { int N = 7, K = 2; int ways = binomial(N - 1, K - 1); cout << "Number of ways to represent " << N << " as the sum of " << K << " non-zero integers: " << ways << endl; return 0; }
輸出
Number of ways to represent 7 as the sum of 2 non-zero integers: 6
複雜度
時間複雜度:O(K)。
空間複雜度:O(1)
結論
在本文中,我們試圖解釋如何找到將N表示為K個非零整數之和的不同方法。我希望這篇文章能幫助你更好地理解這個概念。