两个质数的和是S,它们的积最大是多少?
Input
一个不大于10000的正整数S,为两个质数的和。
Output
一个整数,为两个质数的最大乘积。数据保证有解。
Sample Input
50
Sample Output
589
#include <stdio.h>
#include <math.h>
int Iszs(int n)
{
int i=2;
while(i<=floor(sqrt(n))&&(n%i!=0)) //floor为向下取整函数,sqrt()求平方根
i++;
if(i>floor(sqrt(n)))//若是因为i大于n的平方根而跳出循环,则说明n为质数
return 1;
return 0;
}
int main()
{
int n;
int max=-1;
scanf("%d", &n);
for(int i=2;i<n;i++){
if(Iszs(i)&&Iszs(n-i)){
if(max<i*(n-i))
max=i*(n-i);
}
}
printf("%d\n",max);
return 0;
}
题解:
根据简单的数学原理,两个数的和为S,二者之差越小,则乘积越大。所以要找两个和为S的数字的最大乘积,我们从S/2附近开始找。如果S/2恰能整除,并且S/2是个质数,S/2*S/2就是结果。如果不是,我们再试(S/2)+1与(S/2)-1是否为质数,以此直到试验到一个数最小为2(题目保证有解),或者可以试验到3为止,由于2是质数当中唯一的偶数,可以拿出来单独判断它。
总结此题思路,就是从S/2开始向两边顺序搜索,假设下界lowerbound记为lwbd,上界upperbound叫作upbd,则lwbd=S/2(lwbd是S/2的整除),upbd=S-lwbd,这样lwbd+upbd==s,再定义一个距离S/2距离的变量d,我们希望尽快找到解,对可能的d,从0开始,遍历到S/2,一旦发现lwbd-d与upbd+d同为质数时,就找到了结果,输出(lwbd-d)*(upbd+d).如果一个输入S是奇数,就不需要遍历求解,S是奇数只可能是偶数+奇数,而质数中只有2是偶数,所以直接输出2*(S-2)就是结果.
此题需要反复判断数字是否为质数,如果写一个函数用以判断数字是否为质数,假设有M个数字待判断,那么M次判断都要花费判断质数的函数开销。在参考代码中初始用一个bool数组isPrime[]表示数字i是否为质数,若是质数则isPrime[i]=1,否则isPrime[i]=0,而初始化isPrime[]数组的函数只运行了1次,后续每次判断一个数字是否为质数只需要O(1)的时间,仅需要取得isPrime[]的值就可以了.
#include<stdio.h>
#include<stdbool.h>
const int MAXN=10009;//const:变量不能被改变
bool isPrime[MAXN];
void initPrime()
{
int i,j;
for(i=2;i<MAXN;i++)//数组初始化为true,0和1不是素数,所以直接从2开始
isPrime[i]=true;
for(i=2;i<MAXN;i++)//依次把2,3,4.......的倍数置为false
{
if(isPrime[i]==true)
for(j=i*i;j<MAXN;j+=i)
{
isPrime[j]=false;
}
}
}
int main()
{
initPrime();
int S,x,y;
scanf("%d",&S);
if(S%2==0)//若S为偶数,看中位数是否为素数,若不是 则向两边检测
{
x=S/2;
y=S/2;
while(isPrime[x]==false || isPrime[y]==false)
{
x+=1;
y-=1;
}
printf("%d\n",x*y);
}
else//若S为奇数,定为奇数与偶数的和,因此只能是2,S-2
printf("%d\n",2*(S-2));
return 0;
}