84 lines
2.8 KiB
Python
84 lines
2.8 KiB
Python
|
|
||
|
def build_sets(sets, numbers):
|
||
|
""" Sets is a list of two tuples. Each field represents the sum of the two
|
||
|
sets. For each new number, we can add the number to set one, add the
|
||
|
number to set two, or don't add the number to any sets. If there are no
|
||
|
more numbers we return the list so that we can check if there are tuples
|
||
|
that have the same sum. """
|
||
|
if not numbers:
|
||
|
return sets
|
||
|
current_number, numbers = numbers[0], numbers[1:]
|
||
|
new_sets = []
|
||
|
for t in sets:
|
||
|
new_sets.append(t)
|
||
|
new_sets.append((t[0] + current_number, t[1]))
|
||
|
new_sets.append((t[0], t[1] + current_number))
|
||
|
return build_sets(new_sets, numbers)
|
||
|
|
||
|
|
||
|
def is_condition_one_met(s):
|
||
|
tuples = build_sets([(0, 0)], s)
|
||
|
for a, b in tuples:
|
||
|
if a != 0 and b != 0 and a == b:
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
|
||
|
def is_condition_two_met(s):
|
||
|
""" The second condition says that if |B| > |C| then sum(B) > sum(C). Since
|
||
|
each line is sorted we take the two smallest integers and compare it to the
|
||
|
biggest. Then we take the three smallest integers and compare it to the two
|
||
|
biggest, and so on. Comparing the smallest with the biggest integers is the
|
||
|
worst case and if there is no violation of the condition it will be met for
|
||
|
all other subset pairs. """
|
||
|
half_len = (len(s) - 1) // 2
|
||
|
for i in range(1, half_len + 1):
|
||
|
if not sum(s[:i + 1]) > sum(s[-i:]):
|
||
|
# print(f"{s[:i + 1]=} < {s[-i:]=}")
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
|
||
|
def is_special_sum_set(s):
|
||
|
""" Check for the two conditions and return True if they are both met. """
|
||
|
if not is_condition_two_met(s):
|
||
|
return False
|
||
|
if not is_condition_one_met(s):
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
|
||
|
def next_set_heuristic(xs):
|
||
|
""" Calculate the estimated next optimum based on the formul given in the
|
||
|
question. """
|
||
|
b = xs[(len(xs) - 1) // 2]
|
||
|
next_set = [b]
|
||
|
for a in xs:
|
||
|
next_set.append(a + b)
|
||
|
return next_set
|
||
|
|
||
|
|
||
|
def euler_103():
|
||
|
e_max = 50
|
||
|
min_set = None
|
||
|
for a in range(1, e_max):
|
||
|
for b in range(a + 1, e_max):
|
||
|
for c in range(b + 1, e_max):
|
||
|
for d in range(c + 1, e_max):
|
||
|
for e in range(d + 1, e_max):
|
||
|
for f in range(e + 1, e_max):
|
||
|
for g in range(e + 1, e_max):
|
||
|
s = [a, b, c, d, e, f, g,]
|
||
|
if is_special_sum_set(s):
|
||
|
s_sum = sum(s)
|
||
|
if min_set is None or s_sum < sum(min_set):
|
||
|
min_set = s
|
||
|
return int("".join(map(str, min_set)))
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
solution = euler_103()
|
||
|
print("e103.py: " + str(solution))
|
||
|
assert(solution == 20313839404245)
|
||
|
|