题解 | #素数伴侣#
素数伴侣
https://www.nowcoder.com/practice/b9eae162e02f4f928eac37d7699b352e
import itertools from typing import Iterable PRIME_SET = {2} def is_prime(n: int) -> bool: if n in PRIME_SET: return True if n <= 1: return False for x in range(2, n): if n % x == 0: return False PRIME_SET.add(n) return True def try_match(match_dict, current_x, iterable_2,visited): i_x,x = current_x for i_y,y in enumerate(iterable_2): current_y = (i_y,y) if is_prime(y+x) and current_y not in visited: visited.add(current_y) # 如果Y没有配对,那么配对 | 如果有配对记录,那么尝试重新配对的old_x (match_dict[current_y]) if current_y not in match_dict or try_match(match_dict,match_dict[current_y],iterable_2,visited): # 如果返回真则代表旧的找到了新配对 match_dict[current_y] = current_x return True return False def KM_algorithm(iterable_1,iterable_2): match_dict = {} # 保存 {(index_y,y):(index_x,x), ...} for i_x,x in enumerate(iterable_1): # 寻找可以和iterable2 中配对的数 # 如果所有的iterable2 的数字都配对完成了, 那么该终止循环 if len(match_dict) == len(iterable_2): break visited = set() try_match(match_dict, (i_x,x), iterable_2,visited) # print(match_dict) return len(match_dict) l = int(input()) num_list = list(map(int , input().split())) odd_list = list(filter(lambda x: x%2 ==1 ,num_list)) even_list = list(filter(lambda x: x%2 ==0 ,num_list)) # print(odd_list,even_list) print(KM_algorithm(odd_list,even_list))
不够简洁的回答。匈牙利算法的核心是:
- 从两个列表x,y 中任选一个数。这里从列表x中选择任意一个数a。
- 创建一个集合v (来确保不要重复遍历 列表y里面的元素)和一个字典K,里面用来记录 y元素对应的x元素 类似于{y : x }
- 然后尝试a和另外一个列表y里面寻找可以配对的对象
- 如果 遍历到的y里面的元素b 和a 相加 为质数,且y不在集合v里面,那么就先把这个属于y的元素记录到集合v里,确保没有重复遍历
- 判断b是不是在字典里面,或者 ( K[b] 遍历 (列表y 减去 已访问的元素 集合v)能不能找到新的配对对象)
遍历。。。。 如果b是质数,且没有遍历过: visited 添加 这个b if b not in K or try_match(K, K[b], visited): #K 是保存{y元素:a元素} 这样关系的字典 #K[b] 是当前这个关系里面对应的 a元素的值 K[b] = a return True return False
- 如果二者任意返回真, 那么让字典K保存组合并且返回真
- 全部遍历完都没有返回真,那么就找不到关系,返回False