def solution(banana_list): loop_memo = {} edge_map = {i: [] for i in range(len(banana_list))} for i in range(len(banana_list)): for j in range(i+1, len(banana_list)): if check_loop(banana_list[i], banana_list[j], loop_memo): edge_map[i] += [j] edge_map[j] += [i] return len(banana_list) - len(find_maximum_matching(edge_map)) def find_maximum_matching(edge_map): exposed_vertex_list = [i for i in edge_map] matching = {} while len(exposed_vertex_list) >= 2: start = exposed_vertex_list.pop() path, end = find_new_path(edge_map, start, exposed_vertex_list, matching, {}) if end in exposed_vertex_list: update_matching(matching, start, path, end) exposed_vertex_list.remove(end) return matching import copy def find_new_path(edge_map, curr, end_list, matching, color): for neighbor in edge_map[curr]: if neighbor in end_list: return [], neighbor color[curr] = True for neighbor in edge_map[curr]: if neighbor in color: continue temp_color = copy.deepcopy(color) temp_color[neighbor] = True new_path, end = find_new_path(edge_map, matching[neighbor], end_list, matching, temp_color) return [(curr, neighbor)] + new_path, end return [], None def update_matching(matching, start, path, end): new_left = start for left, right in path: matching[new_left] = left matching[left] = new_left new_left = right matching[new_left] = end matching[end] = new_left # How check_loop works # 1. (ac, bc) => (2ac, bc-ac) = (a, b) => (2a, b-a) # * a < b # 1. (ac, bc+d) => (2ac, bc+d-ac) = (2ac, (b-a)c+d) # * a < b and 0 < d < c # 1. (a, 2n-a) => (2a, 2n-2a) = (a, n-a) # * a < n # 1. therefore, (x, y) will loop iff (x + y) % 2 == 1 # * x and y are relative prime number def check_loop(x, y, memo): if (x, y) in memo: return memo[(x, y)] return bin((x + y)/gcd(x, y)).count('1') != 1 def gcd(m, n): while n != 0: t = m % n m, n = n, t return m tests = [ ([1], 1), ([1, 1], 2), ([1, 7, 3, 21, 13, 19], 0), #([1 for i in range(100)], 100), #([2**(i+1) - 1 for i in range(10)], 2), #([2**(i+1) - 1 for i in range(20)], 2), ] for i, o in tests: result = solution(i) print(i, result == o, result, o)