整數劃分為多數之和

君夢如煙Brian發表於2020-11-14

題目簡述

將整數n,劃分為m個整數的和 ( 1 ≤ m ≤ n ) (1 \le m \le n) (1mn),求有多少種加法結果。

  • 額外條件: 整數的順序也影響結果。

解決方案

解法一、列舉

思考

聯想到抽屜原理

  • 將整數n理解為有n個item,將列舉過程理解為,將n個item放到m個抽屜中

  • 現在的問題就在於如何分配item?

容易得出,兩種極端情況。

  1. m = n m = n m=n抽屜數等於item個數,這意味著只有一種分法
  2. m = 1 m = 1 m=1,只有一個抽屜,怎麼分都也是隻有一種分法

那麼,就剩下一種最一般的情況了。

  1. n > m n > m n>m, 抽屜的個數小於item個數
    思路:先給每個抽屜都派一個item,盈餘的item數surplus為 n − m n - m nm,
    然後,將surplus按照其公因數分配到抽屜中(那麼k個公因數也就有k種抽屜分配情況),構造出所有的抽屜,再計算所有抽屜的組合數之和,即計算結果。
  • 注意:對於由於 n > m n > m n>m 即使是加上盈餘也存在越界的可能,那麼當其越界的時,從列表的首元素開始加即可。

python程式碼實現:


from itertools import permutations


def combines_of_set(_set):
    return len(set(permutations(_set, len(_set))))


def get_cnt(_desk, _num):
    if _desk == 1:  # 特殊情況只有一個抽屜
        return 1

    cnt = 0   # 計數當前所有排列可能
    surplus = _num - _desk    # 給每個抽屜分配一個item後的盈餘的個數

    if surplus == 0:  # 特別情況無盈餘
        return 1

    shares = (x for x in range(1, surplus + 1) if surplus % x == 0)    # 盈餘個數的可劃分份數集

    for x in shares:
        tmp = surplus
        items = [1] * _desk    # 生成抽屜並向每個抽屜放入一個item

        index = 0
        while tmp > 0:
            if index == _desk:  # 越界則從頭加
                index = 0
            items[index] += x
            index += 1
            tmp -= x
        cnt += combines_of_set(items)  # 計算序列組合數

    return cnt


def solution():
    cnt = 0
    n = int(input("請輸入整數n:"))
    for i in range(1, n + 1):
        cnt += get_cnt(i, n)

    return cnt

print(solution())


相關文章