153 lines
4.2 KiB
Python
153 lines
4.2 KiB
Python
from functools import cache
|
|
from collections import Counter, defaultdict
|
|
|
|
# pool = Counter(map(int, "000226688"))
|
|
# counted_digits = (0, 2, 6, 8)
|
|
# counts = (3, 2, 2, 2)
|
|
|
|
# 268
|
|
|
|
# 208
|
|
# 60
|
|
# 0
|
|
|
|
|
|
@cache
|
|
def choose_n_unique(counts, n):
|
|
if sum(counts) < n:
|
|
raise "you done fucked up"
|
|
if sum(counts) == n:
|
|
return set([counts])
|
|
out = set([])
|
|
for i, count in enumerate(counts):
|
|
if count <= 0:
|
|
continue
|
|
out.update(
|
|
choose_n_unique(counts[:i] + (count - 1,) + counts[i + 1 :], n)
|
|
)
|
|
return out
|
|
|
|
|
|
def sub(a, b): # a-b
|
|
return tuple(x - y for x, y in zip(a, b))
|
|
|
|
|
|
# print(choose_n_unique(counts, 3))
|
|
# print(find_sums(counts))
|
|
# print(possible_sums((3, 2, 2, 2)))
|
|
|
|
|
|
def has_len_digit(tup, length):
|
|
for t in tup:
|
|
if len(str(t)) == length:
|
|
return True
|
|
return False
|
|
|
|
|
|
# tup_0, tup_1 = (826,), (0, 0, 6, 820)
|
|
|
|
# print(has_len_digit(tup_0, 2))
|
|
# print(has_len_digit(tup_1, 2))
|
|
# exit()
|
|
|
|
|
|
def find_solutions(counted_digits, counts):
|
|
|
|
@cache
|
|
def possible_sums(counts): # sum -> set(tuple(addend))
|
|
if sum(counts) == 0:
|
|
return {0: set()}
|
|
if sum(counts) == 1:
|
|
for i, count in enumerate(counts):
|
|
if count == 0:
|
|
continue
|
|
digit = counted_digits[i]
|
|
out = {digit: set([(digit,)])}
|
|
return out
|
|
|
|
out = defaultdict(set)
|
|
|
|
for i, count in enumerate(counts):
|
|
if count <= 0:
|
|
continue
|
|
digit = counted_digits[i]
|
|
sub = possible_sums(counts[:i] + (count - 1,) + counts[i + 1 :])
|
|
for s, tups in sub.items():
|
|
for tup in tups:
|
|
out[s + digit].add(tuple(sorted((digit,) + tup)))
|
|
# try appending the digit to all sub subms
|
|
for tups in sub.values():
|
|
for tup in tups:
|
|
for j, val in enumerate(tup):
|
|
if j > 0 and val == tup[j - 1]:
|
|
continue
|
|
new_tup = tuple(
|
|
sorted((val * 10 + digit,) + tup[:j] + tup[j + 1 :])
|
|
)
|
|
out[sum(new_tup)].add(new_tup)
|
|
return out
|
|
|
|
out = []
|
|
for counts_0 in choose_n_unique(counts, 3):
|
|
counts_1 = sub(counts, counts_0)
|
|
# print(counts_1)
|
|
possible_0 = possible_sums(counts_0)
|
|
possible_1 = possible_sums(counts_1)
|
|
# print(possible_0.get(268, "nope"))
|
|
# print(possible_1.get(268, "nope"))
|
|
# print()
|
|
for total in possible_0.keys() & possible_1.keys():
|
|
tups_0 = possible_0[total]
|
|
tups_1 = possible_1[total]
|
|
for tup_0 in tups_0:
|
|
for tup_1 in tups_1:
|
|
if not (has_len_digit(tup_0, 1) or has_len_digit(tup_1, 1)):
|
|
continue
|
|
if not (has_len_digit(tup_0, 2) or has_len_digit(tup_1, 2)):
|
|
continue
|
|
if not (has_len_digit(tup_0, 3) or has_len_digit(tup_1, 3)):
|
|
continue
|
|
out.append((tup_0, tup_1))
|
|
return out
|
|
|
|
|
|
# print(find_solutions(counted_digits=(0, 2, 6, 8), counts=(3, 2, 2, 2)))
|
|
import random
|
|
|
|
rng = random.Random(4)
|
|
# best = 100
|
|
# for i in range(1000):
|
|
|
|
# # rng.randint()
|
|
# def r(radius):
|
|
# return rng.randint(-radius, radius)
|
|
|
|
# candidate = find_solutions(
|
|
# counted_digits=(1 + r(1), 2 + r(1), 6 + r(1), 8 + r(1)),
|
|
# counts=(3 + r(1), 2 + r(1), 2 + r(1), 2 + r(1)),
|
|
# )
|
|
# if not candidate:
|
|
# continue
|
|
|
|
# if len(candidate) <= best:
|
|
# best = len(candidate)
|
|
# print("yay")
|
|
# for tup in candidate:
|
|
# print(" ", tup)
|
|
|
|
|
|
def counted_digits_and_counts_from_solution(solution):
|
|
s = str(solution)
|
|
for to_remove in "(), ":
|
|
s = s.replace(to_remove, "")
|
|
print(s)
|
|
print("".join(sorted(s)))
|
|
c = Counter(s)
|
|
counted_digits = tuple(int(k) for k in sorted(c))
|
|
counts = tuple(int(c[k]) for k in sorted(c))
|
|
return counted_digits, counts
|
|
|
|
|
|
print(counted_digits_and_counts_from_solution("((261,), (7, 27, 227)))"))
|
|
print(find_solutions((1, 2, 6, 7), (1, 4, 1, 3)))
|