將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個非零整數之和的不同方法。我希望這篇文章能幫助你更好地理解這個概念。

更新於: 2023年3月23日

638 次瀏覽

啟動你的職業生涯

完成課程獲得認證

開始
廣告