本节探讨由两个满足某些特定条件的素数组成的素数对,包括经典的 孪生素数对 与 逆序素数对 ;
孪生素数对
相差为2的两个素数称为孪生素数对,简称孪生素数;
例如,3和5是一对孪生素数,41和43也是一对孪生素数;
试求出指定区间上的所有孪生素数对;
方案一 之 常规求解:
1.说明:
设置两个变量:当前素数变量i与相邻的前一个素数变量f,在求出当前素数i后,求i与它相邻的前一个素数f的差,如果i-f=2,则f和i为所求的一对孪生素数;
每求出一个素数i并作判断后,要注意把该素数i存储到f,为继续寻求孪生素数对做准备;
2.程序设计:
#include<stdio.h>
#include<math.h>
int main()
{
long c,d,i,j,f=0;
int t,n=0;
printf("求区间[c,d]上的孪生素数对\n");
printf("请输入c,d(c>2):");
scanf("%ld,%ld",&c,&d);
if(c%2==0) /*确保起点c为奇数*/
c++;
for(i=c;i<=d;i+=2)
{
for(t=0,j=3;j<=sqrt(i);j+=2) /*试商判别素数*/
if(i%j==0)
{
t=1;
break;
}
if(t==0) /*t为0表明i为素数*/
{
if(i-f==2)
{
printf("(%ld,%ld)",f,i);
n++;
}
f=i; /*素数i存储到f,为后一判别做准备*/
}
}
printf("\n[%ld,%ld]上共%d对孪生素数。\n",c,d,n);
}
3.程序运行示例:
求区间[c,d]上的孪生素数对
请输入c,d(c>2):2000,2100
(2027,2029)(2081,2083)(2087,2089)
[2001,2100]上共3对孪生素数。
方案二 之 设置数组求解:
1.说明:
应用试商法判定指定区间内的所有素数依次存储到a数组,a数组中相邻元素之差若为2,这两个素数相差为2,即为一对孪生素数;
2.程序设计:
#include<stdio.h>
#include<math.h>
int main()
{
long c,d,i,j;
int t,m,n=0;
static long a[5000];
printf("请输入c,d(c>2):");
scanf("%ld,%ld",&c,&d);
if(c%2==0) /*确保起点c为奇数*/
c++;
for(m=0,i=c;i<=d;i+=2)
{
for(t=0,j=3;j<=sqrt(i);j+=2) /*试商法判别素数*/
if(i%j==0)
{
t=1;
break;
}
if(t==0)
a[++m]=i; /*i为素数给a数组赋值*/
}
for(i=1;i<m;i++)
if(a[i+1]-a[i]==2) /*相邻素数相差为2即输出*/
{
printf("(%ld,%ld)",a[i],a[i+1]);
n++;
}
printf("\n[%ld,%ld]上共%d对孪生素数对。\n",c,d,n);
}
3.程序运行:
请输入c,d(c>2):1000,1100
(1019,1021)(1031,1033)(1049,1051)(1061,1063)(1091,1093)
[1001,1100]上共5对孪生素数对。
注意:
以上两种方法探求孪生素数对,在素数搜索上都是应用试商法,所不同的是:
前者在每搜索到一个素数时立即判别是否为孪生素数对;
后者则把区间上搜索到的所有素数存储在a数组中,再在a数组中从头到尾判定孪生素数对;
逆序素数对
逆序数对:由两个互为逆序数的不同整数组成逆序数对,例如15与51是2位逆序数对,107与701是3位逆序数对;
逆序素数对:如果逆序数对的两个整数都是素数,则称为逆序素数对(有些资料又称为回文素数对),例如13与31是2位逆序素数对,107与701是3位逆序素数对;
输入正整数n(1< n< 10),试统计并输出所有n位逆序素数对,为了避免重复,约定由素数d和r组成的逆序素数对(d,r)的较小数在前较大数在后,即d< r;
1.说明:
应用试商法判别法把指定的n位整数中的所有素数(设共k个)存储在p数组,p[j]是这k个素数中升序排列的第j个(1<=j<=k);
对于素数f=p[j],r=0赋初值,在i(1~n)循环中实施n次取整与取余运算:c=f%10;r=r*10+c;f=f/10;求得素数f=p[j]的逆序数r;
设p[j]< r,注意到素数p[j]随j的增加而增加,为求逆序数r是否为素数,只要使r与所有大于p[j]的素数p[i](j+1<=i<=k)逐个比较:若未出现r=p[j],说明素数p[j]的逆序数r不是大于p[j]的素数,返回试下一个素数p[j];若出现r=p[i],即素数p[j]的逆序数r大于p[j]的素数p[i],则输出逆序素数对(p[j],r),并应用变量m统计逆序素数对的对数;
2.程序设计:
#include<stdio.h>
#include<math.h>
int main()
{
long f,i,j,k,m,r,s,t,p[50000];
int c,d,g,n;
printf("请输入位数n(n>1):");
scanf("%d",&n);
k=s=0;
t=1;
for(j=1;j<=n-1;j++) /*计算最小的n位整数t*/
t=t*10;
for(m=t+1;m<=(10*t-1);m=m+2) /*枚举所有的n位奇数*/
{
if(m%5==0)
continue;
for(g=0,i=2;i<=sqrt(m);i++)
if(m%i==0)
{
g=1;
break;
}
if(g==0)
{
k++;
p[k]=m;
}
}
for(j=1;j<=k-1;j++)
{
f=p[j];
c=f%10;
d=f/t;
if(c<d) /*素数的逆序数比本身小的不考虑*/
continue;
for(r=0,i=1;i<=n;i++)
{
c=f%10;
r=r*10+c; /*r为d的逆序数*/
f=f/10;
}
if(r<p[j]) /*素数的逆序数比本身小的不考虑*/
continue;
for(i=j+1;i<=k;i++)
if(r==p[i]) /*逆序数r是比本身大的素数则输出*/
{
s++;
printf("(%ld):%ld,%ld",s,p[j],r);
if(s%5==0)
printf("\n");
}
}
printf("\n%d位逆序素数对共有%d对。\n",n,s);
}
3.程序运行示例及变通:
请输入位数n(n>1):3
(1):107,701(2):113,311(3):149,941(4):157,751(5):167,761
(6):179,971(7):199,991(8):337,733(9):347,743(10):359,953
(11):389,983(12):709,907(13):739,937(14):769,967
3位逆序素数对共有14对。
变通:试把程序中r与素数p[i](j+1<=i<=k)的比较循环修改为p[i](j<=i<=k),即素数p[j]的逆序数r也要与其本身p[j]比较,若有r=p[j],意味着素数p[j]的逆序数r就是其本身,此时素数p[j]即为对称素数;
这一修改后,其输出自然包含了前面论述过的“对称素数”,例如输入n=3,则输出有29对,除了以上的14对逆序素数对之外,还加上15个3位对称素数;
顺便指出,网上有资料称Card经计算发现:“有13对3位回文素数对。”这一结论明显少了一对,应更正为14对;