当前位置 博文首页 > Superb_day:多方法求素数(定义法、埃氏法、欧氏法)

    Superb_day:多方法求素数(定义法、埃氏法、欧氏法)

    作者:[db:作者] 时间:2021-09-21 15:08

    一、概述

    素数,又称质数,一个你小学到现在都十分苦恼的老朋友。

    我上小学的时候,老师告诉我说把这个数用已经知道的素数从小到大一点一点试,假如说如果都不能除尽,那它就是个素数。前两天偶然辅导一个小学生的数学作业,发现几乎都使用素数表这个东西。(确实这种东西也比较玄学)

    那程序如何实现的呢?主要分为三个方法:定义筛法、埃氏筛法、欧氏筛法。各有用途,大家自行理解和使用。

    二、定义筛法

    定义法是三种方法里比较容易理解的,它也正如它的名字所描述。

    原理:根据定义来找素数。

    我们来看一下代码:

    bool isprime(int n)//是则返回真,不是则为假 
    {
    	int i=2;//1因为我们人为定义它不是素数,而且1也会陷入死循环 
    	while (i<=sqrt(n)&&n%i!=0) ++i;//当它不超过n的平方根时,用n一个一个试; 
    	if(i<=sqrt(n))return 0;//没经受住上述历练 
    	else return 1;//通关 
    }

    细心的朋友可能已经发现一个问题,为什么i<=n的算数平方根???

    我们来举一个简单的例子:

    假如我们要求 12?这个数是不是一个素数,我们先分析 12?这个数有什么构成。

    可以由1*12、2*6、或者3*4构成。我们从小往大开始一个个枚举,发现2已经可以;假如我们继续到枚举到12,发现完全没有浪费这个时间的必要。

    我们可以得出以下结论,任何可以由两个数相乘得出的数,只用测试到这两个数最大中的最小就可以,然而让他们两个同时最小的就是开平方。

    三、埃氏筛法

    ?埃氏筛法是数学家埃拉托斯特尼所发明的一种比较稳定的求素数方法,他还可以顺带记录下来沿途的素数,我个人认为有个地方还是很有意思的,这就是智慧的体现和数学的魅力。

    原理:用已经有的素数筛掉未来的非素数。

    话不多说,上代码:

    int slove(int n)
    {
        int p=0;//用来记录素数的多少 
        for(int i=0;i<=n;i++)
            is_prime[i]=true;//先把它初始化
        is_prime[0]=is_prime[1]=false;//人为规定0,1不是素数 
        for(int i=2;i<=n;i++)//枚举 
        {
            if(is_prime[i])//如果它是素数
            {
                prime[p++]=i;//计算素数的个数,也记录下了素数
                for(int j=2*i;j<=n;j+=i)//用它去筛它的素数 
                    is_prime[j]=false;//它的倍数自然不是质数 
            }
        }
        return p;//返回多少个素数 
    }

    ?

    四、欧式筛法

    欧拉函数求法与欧拉筛法求素数也是非常精妙的算法。

    欧拉函数是小于n的正整数中与n互质的数的数目,欧式筛法正是围绕着欧拉函数而展开。

    原理:以欧拉函数为本体,衍生操作欧式筛法

    我们还需要了解一下特性:
    1.若a为质数,phi[a]=a-1;
    2.若a为质数,b mod a=0,phi[a*b]=phi[b]*a
    3.若a,b互质,phi[a*b]=phi[a]*phi[b](当a为质数时,if b mod a!=0 ,phi[a*b]=phi[a]*phi[b])

    当然,信息学只要求你会用,不要求你会证明,实在不行就把结论背下来吧。

    这是一种比较玄学的算法,理解起来有些困难,建议手打模拟。

    int n,m[100],phi[100],p[100],nump;
    //m[i]标记i是否为素数,0为素数,1不为素数;p是存放素数的数组;nump是当前素数个数;phi[i]为欧拉函数(小于它并与它互质的个数)
    int make()
    {
            phi[1]=1;//人为规定1不是素数 
        for (int i=2;i<=n;i++)//记录2至n的所有细节 
        {
            if (!m[i])//假如i为素数
            {
                p[++nump]=i;//将i加入素数数组p中
                phi[i]=i-1;//因为i是素数,由特性1得知    
            }    
            for (int j=1;j<=nump&&p[j]*i<n;j++)  //用当前已得到的素数数组p筛,筛去p[j]*i
            {
                m[p[j]*i]=1;//可以确定i*p[j]不是素数 
                if (i%p[j]==0) //看p[j]是否是i的约数,因为素数p[j],等于判断i和p[j]是否互质 
                {
                    phi[p[j]*i]=phi[i]*p[j]; //特性2
                    break;
                }
                else phi[p[j]*i]=phi[i]*(p[j]-1); //互质,特性3其,p[j]-1就是phi[p[j]]   
            }
        }
    }

    ?

    cs
    下一篇:没有了