Ну тогда примерно так. Приправить, добавить thread-safety, избавиться от рекурсии и дичайшего выделения памяти по своему вкусу:
def solve(buckets: list[frozenset[int]], pool: frozenset[int], sum_: int, solved: set[frozenset[frozenset[int]]], tried: set[frozenset[frozenset[int]]]):
assert all(x <= sum_ for x in pool)
tried.add(frozenset(buckets))
if not pool and set(sum(bucket) for bucket in buckets) == {sum_} and len(set(len(b) for b in buckets)) == 1:
solved.add(frozenset(buckets))
for x in pool:
for i, bucket in enumerate(buckets):
new_buckets = buckets[:]
new_buckets[i] = bucket | {x}
if frozenset(new_buckets) not in tried:
solve(new_buckets, pool - {x}, sum_, solved, tried)
return solved
if __name__ == '__main__':
for solution in solve([frozenset(), frozenset()], frozenset([1,2,3,4,5,6,7,8]), 18, set(), set()):
print(solution)
А ещё это полный перебор. Жадные, щедрые и другие решения ищите где-нибудь
здесь