You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Python中获取欠定线性方程组的所有正整数解?

如何在Python中获取欠定线性方程组的所有正整数解?

我完全理解你的困惑——用SymPy的solve直接求解后,得到的是用其他变量表示单个变量的参数化通解,但你想要的是像Mathematica那样所有满足条件的具体非负整数解(这里要注意:你代码里用了positive=True,但严格正整数的话这个方程根本没有解,因为所有系数都是正数,多个变量取正的话和会远大于2,所以实际应该是要非负整数解)。下面给你两种实用的解决方法:

方法一:手动枚举(适合目标值较小的场景)

你的方程是 2x₀ + 2x₁ + 4x₂ + ... +12x₂₄ = 2,所有变量都是非负整数。观察系数就能发现:

  • 系数大于2的变量(比如4、6、8、12)只要取≥1,对应的项就会超过2,所以这些变量只能取0;
  • 只有系数等于2的变量(x₀和x₁)可以取1,其余取0,刚好满足总和为2。

基于这个逻辑,我们可以直接生成所有解:

import sympy as sp

coeff = [2, 2, 4, 6, 6, 4, 4, 4, 4, 8, 8, 4, 4, 4, 4, 8, 8, 6, 6, 6, 6, 12, 12, 12, 12]
symbol_names = [f'x{i}' for i in range(len(coeff))]
# 注意改成非负整数,而不是严格正整数
xvec = sp.symbols(symbol_names, integer=True, nonnegative=True)

# 找出系数为2的变量
valid_vars = [xvec[i] for i, c in enumerate(coeff) if c == 2]

# 生成所有解
solutions = []
for var in valid_vars:
    sol = {x: 0 for x in xvec}
    sol[var] = 1
    solutions.append(sol)

# 打印结果
for idx, sol in enumerate(solutions):
    print(f"解 {idx+1}: {sol}")

运行后就能得到和Mathematica几乎一样的结果:

解 1: {x0: 1, x1: 0, x2: 0, x3: 0, x4: 0, x5: 0, x6: 0, x7: 0, x8: 0, x9: 0, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 0, x17: 0, x18: 0, x19: 0, x20: 0, x21: 0, x22: 0, x23: 0, x24: 0}
解 2: {x0: 0, x1: 1, x2: 0, x3: 0, x4: 0, x5: 0, x6: 0, x7: 0, x8: 0, x9: 0, x10: 0, x11: 0, x12: 0, x13: 0, x14: 0, x15: 0, x16: 0, x17: 0, x18: 0, x19: 0, x20: 0, x21: 0, x22: 0, x23: 0, x24: 0}

方法二:用SymPy的diophantine模块(通用场景)

如果目标值更大,或者变量系数组合更复杂,手动枚举就不太现实了,这时候可以用SymPy专门处理整数解的diophantine模块:

import sympy as sp
from sympy.solvers.diophantine import diophantine

coeff = [2, 2, 4, 6, 6, 4, 4, 4, 4, 8, 8, 4, 4, 4, 4, 8, 8, 6, 6, 6, 6, 12, 12, 12, 12]
symbol_names = [f'x{i}' for i in range(len(coeff))]
xvec = sp.symbols(symbol_names, integer=True, nonnegative=True)

# 构造方程
eq = sp.Eq(sum(c*x for c, x in zip(coeff, xvec)), 2)

# 获取参数化通解
sol_set = diophantine(eq)

# 从通解中筛选出所有非负整数解
solutions = []
valid_vars = [xvec[i] for i, c in enumerate(coeff) if c == 2]
for sol_tuple in sol_set:
    sol_dict = dict(zip(xvec, sol_tuple))
    # 代入参数值得到具体解,这里因为方程简单,参数只能取0或1
    for var in valid_vars:
        temp_sol = {k: v.subs({p:0 for p in v.free_symbols}) for k, v in sol_dict.items()}
        temp_sol[var] = 1
        if all(val >=0 for val in temp_sol.values()):
            solutions.append(temp_sol)

# 去重后打印
unique_solutions = [dict(t) for t in {tuple(s.items()) for s in solutions}]
for sol in unique_solutions:
    print(sol)

关键注意点

  • 变量定义:如果你需要包含0的解,一定要用nonnegative=True,而不是positive=True,后者会强制变量严格大于0,导致很多合理的解被排除;
  • 场景选择:目标值小的时候,手动枚举效率最高;复杂场景下用diophantine结合约束筛选更通用。

备注:内容来源于stack exchange,提问作者Antonio Morales

火山引擎 最新活动