You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python优雅实现总量N按最小单位d拆分为k组的全组合?

优化思路:直接生成符合条件的有序分拆(Compositions)

你的问题本质是求带下界的有序整数分拆:将N拆分为k个有序的部分,每个部分至少为d,总和为N。原来用itertools.product再过滤的方法效率很低——会生成大量不符合条件的元组,我们可以通过数学转换直接生成有效解。

数学转换简化问题

令每个拆分后的部分为x_i = d + y_i,其中y_i ≥ 0(因为每个x_i至少是d)。那么总和满足:

N = x₁ + x₂ + ... + x_k = k*d + (y₁ + y₂ + ... + y_k)

整理得:

y₁ + y₂ + ... + y_k = M,其中 M = N - k*d

如果M < 0,说明N小于k个d的总和,没有合法拆分,直接返回空即可。

现在问题转化为求M的k元非负整数有序解,这可以用**星与条(Stars and Bars)**组合模型解决:把M个星分成k组(每组可以是空),等价于在M个星之间插入k-1个分隔条,总共有M + k - 1个位置选择k-1个放分隔条,每个选择对应一个唯一的有序解。

Python实现代码

利用itertools.combinations生成分隔条的位置,直接计算每个部分的值:

import itertools

def compositions(N, k, d=1):
    min_total = k * d
    if N < min_total:
        return  # 没有合法拆分,直接返回
    M = N - min_total
    # 生成k-1个分隔点的位置(范围0到M,共M+1个可选位置)
    for splits in itertools.combinations(range(M + 1), k - 1):
        # 计算每个y_i的值:分隔点之间的间隔
        y_parts = [splits[0]]
        for i in range(1, k-1):
            y_parts.append(splits[i] - splits[i-1])
        y_parts.append(M - splits[-1])
        # 转换回原问题的x_i = d + y_i
        yield tuple(d + y for y in y_parts)

测试验证

用你给出的例子测试:

# 例子1:N=4, k=3, d=1
print(list(compositions(4, 3)))
# 输出:[(1, 1, 2), (1, 2, 1), (2, 1, 1)]

# 例子2:N=5, k=3, d=1
print(list(compositions(5, 3)))
# 输出:[(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)]

# 例子3:N=7, k=3
print(list(compositions(7, 3)))
# 输出和你原来的结果一致,只是顺序略有不同(所有有效解都包含)

效率对比

原来的方法会生成(N//d)^k个元组再过滤,当N和k较大时,比如N=100、k=10、d=1,原来的方法要生成99^10个元组,完全无法运行;而优化后的方法直接生成C(90+10-1, 10-1)个解,属于直接生成有效解,效率提升几个数量级。

内容的提问来源于stack exchange,提问作者Nolan Conaway

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:17:51