HJ28 素数伴侣【python3】

题目描述

若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的 N ( N 为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。

输入:
有一个正偶数 n ,表示待挑选的自然数的个数。后面给出 n 个具体的数字。
输出:
输出一个整数 K ,表示你求得的“最佳方案”组成“素数伴侣”的对数。

数据范围: 1 ≤ n ≤ 100 1≤n≤100 1n100 ,输入的数据大小满足 2 ≤ v a l ≤ 30000 2≤val≤30000 2val30000

输入描述

1 输入一个正偶数 n
2 输入 n 个整数

输出描述

求得的“最佳方案”组成“素数伴侣”的对数。

代码

递归法 4/24

OJ提交超时,本地IDE运行答案正确。思路如下:
1、定义判断是否为素数的函数
2、定义计算素数伴侣数量的递归函数
3、两层循环遍历全排列。每次从输入数据中提出两个数据,若是素数伴侣,则数量ans+1,继续执行函数。当只剩下两个数的时候,判断是否为素数伴侣后退出递归。列表res记录所有组合的素数伴侣数量,取出最大值

N=int(input())
L=list(map(int,input().split()))

# 判断是否为素数
def is_prime(n):
    if n==2:
        return 1
    elif n==1:
        return 0
    for i in range(2,int(n**0.5)+1):
        if n%i==0:
            return 0
    return 1

# 在数字列表number中找出素数伴侣的组合
res=[]
def f(number,ans):
    N=len(number)
    #print(number,N)
    if N==2:
        if is_prime(number[0]+number[1])==1:
            res.append(ans+1)
        else:
            res.append(ans)
        return 'finish'
    elif N>2 and N%2==0:
        for i in range(N-1):
            for j in range(i+1,N):
                if is_prime(number[i]+number[j])==1:
                    f(number[:i]+number[i+1:j]+number[j+1:],ans+1)
                else:
                    f(number[:i]+number[i+1:j]+number[j+1:],ans)



f(L,0)
print(len(res))
#print(res)

# 输出答案
print(max(res))

优化1 4/24

偶数除2以外都是合数,而奇数+奇数,偶数+偶数都等于偶数。只有奇数+偶数才有可能是质数。
又本题输入的数都是大于等于2的,所以本题构成素数伴侣的数只能是“奇数+偶数”的组合。因此最佳方案,即为该种组合中素数的个数。
因此,将输入的数据以奇偶分开存储。
OJ仍然在第五个用例提交超时,但是在本地IDE运行, 导入datetime库可以看到运行时间从22s降到了10s。len(res)可以看出递归次数也少了很多。。。只不过还是超时

N=int(input())
L=list(map(int,input().split()))

L_o=[] #L中的奇数
L_e=[] #L中的偶数
for i in range(N):
    if L[i]%2==0:
        L_e.append(L[i])
    else:
        L_o.append(L[i])

# 判断是否为素数
def is_prime(n):
    if n==2:
        return 1
    elif n==1:
        return 0
    for i in range(2,int(n**0.5)+1):
        if n%i==0:
            return 0
    return 1

# 在数字列表number中找出素数伴侣的组合
res=[]
def f(number1,number2,ans):
    # number1记录更短的列表
    N1=len(number1)
    N2=len(number2)
    if N1>N2: 
        tmp=number1
        number1=number2
        number2=tmp

    # 奇+偶组合匹配完毕 退出循环
    if N1==0:
        res.append(ans)
        return 'finish'
    else:
        for i in range(N1):
            for j in range(N2):
                if is_prime(number1[i]+number2[j])==1:
                    f(number1[:i]+number1[i+1:],number2[:j]+number2[j+1:],ans+1)
                else:
                    f(number1[:i]+number1[i+1:],number2[:j]+number2[j+1:],ans)

# 输出答案
if len(L_o)>0 and len(L_e)>0:
    f(L_o,L_e,0)
    print(max(res))
else:
    print(0)

优化2 7/24

在优化1的基础上。因为是要计算最佳方案,所以可这么做:如果取定较短列表的一个数,和另一个列表的所有数都不构成素数伴侣,直接开始匹配较短列表的第二个数,减少递归次数。
就算构成素数伴侣,下一次递归较短数列也可以直接从第二个数开始。
通过了7/24测试用例,OJ提交还是超时。

N=int(input())
L=list(map(int,input().split()))

L_o=[] #L中的奇数
L_e=[] #L中的偶数
for i in range(N):
    if L[i]%2==0:
        L_e.append(L[i])
    else:
        L_o.append(L[i])
# 替换,用L_o记录更长的数据
if len(L_o)>len(L_e): 
    tmp=L_o
    L_o=L_e
    L_e=tmp

# 判断是否为素数
def is_prime(n):
    if n==2:
        return 1
    elif n==1:
        return 0
    for i in range(2,int(n**0.5)+1):
        if n%i==0:
            return 0
    return 1

# 在数字列表number中找出素数伴侣的组合
res=[]
def f(number1,number2,ans):
    # number1记录更短的列表
    N1=len(number1)
    N2=len(number2)


    # 奇+偶组合匹配完毕 退出循环
    if N1==0:
        res.append(ans)
        return 'finish'
    else:
        for i in range(N1):
            flag=0
            for j in range(N2):
                if is_prime(number1[i]+number2[j])==1:
                    flag=1
                    f(number1[i+1:],number2[:j]+number2[j+1:],ans+1)
            if flag==0:
                f(number1[i+1:],number2,ans)

# 输出答案
if len(L_o)>0 and len(L_e)>0:
    f(L_o,L_e,0)
    print(max(res))
else:
    print(0)

贪心

记录每一个奇数以及每一个偶数,和输入的所有偶数以及奇数,能够配对成功素数伴侣的个数。
每次删除能够配对的最小的奇数和与之配对的第一个偶数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值