最大切分乘積問題¶
Question
給定一個正整數 \(n\) ,將其切分為至少兩個正整數的和,求切分後所有整數的乘積最大是多少,如下圖所示。
假設我們將 \(n\) 切分為 \(m\) 個整數因子,其中第 \(i\) 個因子記為 \(n_i\) ,即
本題的目標是求得所有整數因子的最大乘積,即
我們需要思考的是:切分數量 \(m\) 應該多大,每個 \(n_i\) 應該是多少?
貪婪策略確定¶
根據經驗,兩個整數的乘積往往比它們的加和更大。假設從 \(n\) 中分出一個因子 \(2\) ,則它們的乘積為 \(2(n-2)\) 。我們將該乘積與 \(n\) 作比較:
如下圖所示,當 \(n \geq 4\) 時,切分出一個 \(2\) 後乘積會變大,這說明大於等於 \(4\) 的整數都應該被切分。
貪婪策略一:如果切分方案中包含 \(\geq 4\) 的因子,那麼它就應該被繼續切分。最終的切分方案只應出現 \(1\)、\(2\)、\(3\) 這三種因子。
接下來思考哪個因子是最優的。在 \(1\)、\(2\)、\(3\) 這三個因子中,顯然 \(1\) 是最差的,因為 \(1 \times (n-1) < n\) 恆成立,即切分出 \(1\) 反而會導致乘積減小。
如下圖所示,當 \(n = 6\) 時,有 \(3 \times 3 > 2 \times 2 \times 2\) 。這意味著切分出 \(3\) 比切分出 \(2\) 更優。
貪婪策略二:在切分方案中,最多隻應存在兩個 \(2\) 。因為三個 \(2\) 總是可以替換為兩個 \(3\) ,從而獲得更大的乘積。
綜上所述,可推理出以下貪婪策略。
- 輸入整數 \(n\) ,從其不斷地切分出因子 \(3\) ,直至餘數為 \(0\)、\(1\)、\(2\) 。
- 當餘數為 \(0\) 時,代表 \(n\) 是 \(3\) 的倍數,因此不做任何處理。
- 當餘數為 \(2\) 時,不繼續劃分,保留。
- 當餘數為 \(1\) 時,由於 \(2 \times 2 > 1 \times 3\) ,因此應將最後一個 \(3\) 替換為 \(2\) 。
程式碼實現¶
如下圖所示,我們無須透過迴圈來切分整數,而可以利用向下整除運算得到 \(3\) 的個數 \(a\) ,用取模運算得到餘數 \(b\) ,此時有:
請注意,對於 \(n \leq 3\) 的邊界情況,必須拆分出一個 \(1\) ,乘積為 \(1 \times (n - 1)\) 。
時間複雜度取決於程式語言的冪運算的實現方法。以 Python 為例,常用的冪計算函式有三種。
- 運算子
**
和函式pow()
的時間複雜度均為 \(O(\log a)\) 。 - 函式
math.pow()
內部呼叫 C 語言庫的pow()
函式,其執行浮點取冪,時間複雜度為 \(O(1)\) 。
變數 \(a\) 和 \(b\) 使用常數大小的額外空間,因此空間複雜度為 \(O(1)\) 。
正確性證明¶
使用反證法,只分析 \(n \geq 3\) 的情況。
- 所有因子 \(\leq 3\) :假設最優切分方案中存在 \(\geq 4\) 的因子 \(x\) ,那麼一定可以將其繼續劃分為 \(2(x-2)\) ,從而獲得更大的乘積。這與假設矛盾。
- 切分方案不包含 \(1\) :假設最優切分方案中存在一個因子 \(1\) ,那麼它一定可以合併入另外一個因子中,以獲得更大的乘積。這與假設矛盾。
- 切分方案最多包含兩個 \(2\) :假設最優切分方案中包含三個 \(2\) ,那麼一定可以替換為兩個 \(3\) ,乘積更大。這與假設矛盾。