def solve_linear_diop(total: int, *coeffs: int) -> Iterator[Tuple[int, ...]]:
r"""Yield non-negative integer solutions of a linear Diophantine equation of the format
:math:`c_1 x_1 + \dots + c_n x_n = total`.
If there are at most two coefficients, :func:`base_solution_linear()` is used to find the solutions.
Otherwise, the solutions are found recursively, by reducing the number of variables in each recursion:
1. Compute :math:`d := gcd(c_2, \dots , c_n)`
2. Solve :math:`c_1 x + d y = total`
3. Recursively solve :math:`c_2 x_2 + \dots + c_n x_n = y` for each solution for `y`
4. Combine these solutions to form a solution for the whole equation
Args:
total:
The constant of the equation.
*coeffs:
The coefficients :math:`c_i` of the equation.
Yields:
The non-negative integer solutions of the equation as a tuple :math:`(x_1, \dots, x_n)`.
"""
if len(coeffs) == 0:
if total == 0:
yield tuple()
return
if len(coeffs) == 1:
if total % coeffs[0] == 0:
yield (total // coeffs[0], )
return
if len(coeffs) == 2:
yield from base_solution_linear(coeffs[0], coeffs[1], total)
return
# calculate gcd(coeffs[1:])
remainder_gcd = math.gcd(coeffs[1], coeffs[2])
for coeff in coeffs[3:]:
remainder_gcd = math.gcd(remainder_gcd, coeff)
# solve coeffs[0] * x + remainder_gcd * y = total
for coeff0_solution, remainder_gcd_solution in base_solution_linear(coeffs[0], remainder_gcd, total):
new_coeffs = [c // remainder_gcd for c in coeffs[1:]]
# use the solutions for y to solve the remaining variables recursively
for remainder_solution in solve_linear_diop(remainder_gcd_solution, *new_coeffs):
yield (coeff0_solution, ) + remainder_solution
评论列表
文章目录