题目描述
若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如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 1≤n≤100 ,输入的数据大小满足 2 ≤ v a l ≤ 30000 2≤val≤30000 2≤val≤30000
输入描述
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)
贪心
记录每一个奇数以及每一个偶数,和输入的所有偶数以及奇数,能够配对成功素数伴侣的个数。
每次删除能够配对的最小的奇数和与之配对的第一个偶数