*28 素数伴侣(匈牙利算法)

题目描述
题目描述
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的N(N为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。
输入:
有一个正偶数N(N≤100),表示待挑选的自然数的个数。后面给出具体的数字,范围为[2,30000]。
输出:
输出一个整数K,表示你求得的“最佳方案”组成“素数伴侣”的对数。
输入描述:
输入说明
1 输入一个正偶数n
2 输入n个整数
输出描述:
求得的“最佳方案”组成“素数伴侣”的对数。

思路:素数,除了2是偶数,其他是奇数——而现在不可能出现2了,所以我们只考虑奇数的素数2个数的和是奇数,有什么情况呢?只有奇数+偶数。所以,我们把这些数分成2堆——奇数和偶数,然后在他们中间,和是素数的,连上一条边,然后做匹配。因为对二分图的最大匹配,有一个简单很多的算法,匈牙利算法。二分图就是,你可以把图上的点分成2堆,每堆之内的点不会有边,2堆之间,才可能连边。换句话说,一条边,必定连2个来自不同堆的点。现在,对每条边,一定连一个奇数,一个偶数,点能按奇数和偶数分成两部分,刚好就是二分图嘛!
匈牙利算法:https://blog.csdn.net/sunny_hun/article/details/80627351

import math
def prime_judge(n):
    if n>1:
        m = int(math.sqrt(n))
        if n % 2 == 0:#将2及所有合数因子排除掉
            return False
        else:
            for i in range(m + 1)[3::2]:#从3起步,步长为2
                if n % i == 0:
                    return False
        return True
    return False


def group_lst(lst):  ##分奇偶
    odd = []
    even = []
    for i in lst:
        if int(i) % 2 == 1:
            odd.append(int(i))
        else:
            even.append(int(i))
    return (odd, even)


def matrix_ab(a, b):
    matrix = [[0 for i in range(len(b))] for i in range(len(a))]
    for ii, i in enumerate(a):
        for jj, j in enumerate(b):
            if prime_judge(i + j) == True:#和为素数,则对应索引标为1
                matrix[ii][jj] = 1
    return matrix


def find(x):#匈牙利算法从b中为x找匹配
    for index, i in enumerate(b):#遍历b中每个元素
        if matrix[x][index] == 1 and used[index] == 0:#如果有素数搭配连接并且无标记(标记的十一时这次曾试图改变归属,但没有成功)
            used[index] = 1
            if connect[index] == -1 or find(connect[index]) != 0:#b中元素无连接或能腾出位置
                connect[index] = x#为b匹配
                return 1
    return 0


while True:
    try:
        n = int(input())
        m = input().split()
        (a, b) = group_lst(m)
        matrix = matrix_ab(a, b)
        connect = [-1 for i in range(len(b))]
        count = 0
        for i in range(len(a)):
            used = [0 for j in range(len(b))]
            if find(i):
                count += 1
        print(count)
    except:
        break
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值