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)