Fork me on GitHub

大范围内高效查找回文质数(回文数猜想)

人们认为,回文数中存在无穷多个素数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;
}

这里写图片描述




【附:一文一图】
这里写图片描述

posted @ 2017-10-07 17:22  zhouie  阅读(1452)  评论(0编辑  收藏  举报