大范围内高效查找回文质数(回文数猜想)
人们认为,回文数中存在无穷多个素数11,101,131,151,191……。除了11以外,所有回文素数的位数都是奇数。道理很简单:如果一个回文素数的位数是偶数,则它的奇数位上的数字和与偶数位上的数字和必然相等;根据数的整除性理论,容易判断这样的数肯定能被11整除,所以它就不可能是素数。
最初几个回文素数:11,101,131,151,181,191,313,353,373,383,727,757,787,797,919,929……两位回文素数1个,三位回文素数15个,五位回文素数93个,七位回文素数668个,九位回文素数5172个。
/*题目描述
因为151既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 151 是回文质数。
写一个程序来找出范围[a,b](5 <= a < b <= 100,000,000)( 一亿)间的所有回文质数;
输入输出格式
输入格式:
第 1 行: 二个整数 a 和 b .
输出格式:
输出一个回文质数的列表,一行一个。
输入样例:
5 500
输出样例:
5
7
11
101
131
151
181
191
313
353
373
383
*/
思路:先定义两个判断函数,一个用于判断一个整数M是否为质数(is_ prime),一个用于判断一个整数M是否为回文数(is_hws)
按照下面的程序块去执行样例(5 99999999)总耗时:9.134秒,还算可以,没有超时。
做个测试!交换一下两个判断函数的位置后(即先判断素数在判断回文数)再去执行样例(5 99999999)总耗时:38.854秒
分析原因,可能是花在判断质数的时间太长了!
#include<bits/stdc++.h>
using namespace std;
int is_hws(int num)
{
int m=num,sum=0;
while (m)
{
sum = sum*10 + m%10;
m /= 10;
}
if (sum == num)
return 1;
else
return 0;
}
int is_prime(int s)
{
if(s==0||s==1)
{
return 0;
}
if(s==2)
{
return 1;
}
for(int i=2; i*i<=s; i++)
{
if(s%i==0)
{
return 0;
}
}
return 1;
}
int ws(int k) //位数
{
if(k>=10 && k<100 && k!=11 || k>=1000 && k<10000)return 0;
if(k>=100000 && k<1000000 || k>=10000000 && k<100000000)return 0;
return 1;
}
/*
之所以先找回文数(并依据尾数筛选掉那些不符的)再在回文数中找素数
是因为那样的回文数比素数数量要少
*/
int main()
{
long long a,b;
cin>>a>>b;
if(b>10000000) b/=10;
for(int i=a;i<=b;i++)
{
if(ws(i)&&is_hws(i))
{
if(is_prime(i))
cout<<i<<endl;
}
}
return 0;
}
那么,还有没有别的什么方法来进一步优化呢
思考一下!如果回文数用循环生成,这样就不用判断回文数了~
说明
提示 1: 找出所有的回文数再判断它们是不是质数(素数).
提示 2: 要产生正确的回文数,你可能需要几个像下面这样的循环。
eg.产生长度为5的回文数:
for (d1 = 1; d1 <= 9; d1+=2) { // 只有奇数才会是素数
for (d2 = 0; d2 <= 9; d2++) {
for (d3 = 0; d3 <= 9; d3++) {
palindrome = 10000*d1 + 1000*d2 +100*d3 + 10*d2 + d1;//(处理回文数...)
}
}
}
1)1位回文质数只有5,7;2位回文质数只有11。因此此部分可以直接打表。
2)可以证明不存在4,6,8位(以及更大偶数位)的回文质数,因此此部分可以忽略。
3)按照题目要求的范围,9位数最多只有100000000一个数,而且不是回文质数,因此此部分可以忽略。
4)注意每一个打表或构造得到的回文数,要判断是否在闭区间[m,n]内。小于m就continue,大于n就return 0(因为此后所有数一定都大于n)。
5)每个经过上述四步得到的回文数,输出并换行即可。
#include<bits/stdc++.h>
using namespace std;
bool ispr(int n)
{
for(int k=2;k<=sqrt(n);++k)
if(n%k==0)
return false;
return true;
}
int getsize(int n)
{
int m=1,k=n;
while(k>9)
{
k/=10;
++m;
}
return m;
}
int main()
{
int l,m,n,q,w,i,j,k;
cin>>m>>n;
q=getsize(m);
w=getsize(n);
if(q<=1&&w>=1)
{
if((m<=5)&&(n>=5))
cout<<5<<endl;
if((m<=7)&&(n>=7))
cout<<7<<endl;
}
if((q<=2)&&(w>=2))
{
if((m<=11)&&(n>=11))
cout<<11<<endl;
}
if((q<=3)&&(w>=3))
{
for(int a=1;a<=9;a+=2)
for(int b=0;b<=9;++b)
{
int f=a*100+b*10+a;
if(f<m)
continue;
if(f>n)
return 0;
if(ispr(f))
cout<<f<<endl;
}
}
if((q<=5)&&(w>=5))
{
for(int a=1;a<=9;a+=2)
for(int b=0;b<=9;++b)
for(int c=0;c<=9;++c)
{
int f=a*10000+b*1000+c*100+b*10+a;
if(f<m)
continue;
if(f>n)
return 0;
if(ispr(f))
cout<<f<<endl;
}
}
if((q<=7)&&(w>=7))
{
for(int a=1;a<=9;a+=2)
for(int b=0;b<=9;++b)
for(int c=0;c<=9;++c)
for(int d=0;d<=9;++d)
{
int f=a*1000000+b*100000+c*10000+d*1000+c*100+b*10+a;
if(f<m)
continue;
if(f>n)
return 0;
if(ispr(f))
cout<<f<<endl;
}
}
return 0;
}
【附:一文一图】