zoukankan      html  css  js  c++  java
  • 素数的判断(大数据,大规模)

    素数的判断其实谁都会,所以这篇跳过简单的素数判断,直接学习如何快速判断1到N的素数,以及判断大数据是否为素数。

     (1)埃氏筛法

    现在我们先学习埃氏筛选法,此法实用与大规模判断素数,比如1到N的素数有那些啊,等等等等。

    这个算法流弊哦,与辗转相除法一样古老哇。

    首先,将2到n范围内的所有整数写下来。其中最小的数字2是素数,将表中2的倍数都划去。表中剩余的最小数字是3,不能被更小的数整除,是素数。如果表中最小的是m,m为素数,将m的倍数划去。

     附上表格学习:

    2 3 4 5 6 7 8 9 10 11 12
    2 3 - 5 - 7 - 9 - 11 -
    2 3 - 5 - 7 - - - 11 -

    #include<stdio.h>
    #define MAX 1000000
    bool is[MAX];///判断
    int pr[MAX];///储存素数
    ///返回1到n有多少个素数,以及储存
    int sieve(int n)
    {
        int p=0;
        ///初始化让他们高兴一下先
        for(int i=0 ; i<=n ;i++)
            is[i]=true;
            is[0]=is[1]=false;///根本都不是自己人
            for(int i=2 ; i<=n ; i++)
            {
                ///如果是自己人
                if(is[i])
                {
                    ///我就记录咯
                    pr[++p]=i;
                    ///那现在就很明显了,关于自己人I的倍数都不是自己人了
                    for(int j=i*2 ; j<=n ; j+=i)
                        is[j]=false;
                }
            }
            return p;
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        printf("%d
    ",sieve(n));
        return 0;
    }
    View Code

    往往题目不会那么简单,现在来搞一个难一点的区间筛法哼哼。。。。

    求区间[a,b]内的素数个数,哇哈哈哈。

    b以内的合数一定不会超过根号b,如果有根号b以内的素数表的话,那我们就可以把它运用到(a,b]上。也就是说我们要先搞出[ 2 ,根号b] 的表与[ a , b ]的表,然后在从[ 2 , 开B ]的表中筛选出素数的同时,也将其倍数在[ a , b ]的表中划去,流弊吧。

    #include<stdio.h>
    #define MAX 1000007
    #define ll long long
    bool issmall[MAX];///[2,sqrt(b]
    bool is[MAX];///[a,b]
    void seg(ll a,ll b)
    {
        ll i,j;
        ///对[2,sqrt(b))的初始化全为质数
        for( i=0 ; i*i<b ; i++)
            issmall[i]=true;
        ///对下标偏移后的[a,b)进行初始化
        for( i=0 ; i<b-a ; i++)
            is[i]=true;
            ///在筛选[2,sqrt(b)],在筛选这个区间的同时,将大区间的也搞了
        for( i=2 ; i*i<b ; i++)
        {
            if(issmall[i])
            {
                for( j=2*i ; j*j<b ; j+=i)
                    issmall[i]=false;///不是自己人
                 ///(a+i-1)/i得到最接近a的i的倍数,最低是i的2倍,然后筛选
                for( j=(a+i-1)/i*i ; j<b ;j+=i )
                    is[j-a]=false;
            }
        }
    }
    int main()
    {
        ll a,b;
        while(scanf("%lld%lld",&a,&b)!=EOF)
        {
            seg(a,b);
            ll cnt=0;
            for(ll j=0 ; j<b-a ; j++)
            {
                if(is[j])
                {
                    cnt++;
                }
            }
    
            if(a==1)
                cnt--;
            printf("%d
    ",cnt);
        }
    }
    View Code

    素不素很流弊勒,现在来实战下;

    题意:给定两个素数n和m,要求把n变成m,每次变换时只能变一个数字,即变换后的数与变换前的数只有一个数字不同,并且要保证变换后的四位数也是素数。求最小的变换次数;如果不能完成变换,输出Impossible。

    无论怎么变换,个位数字一定是奇数(个位数字为偶数肯定不是素数),这样枚举个位数字时只需枚举奇数就行;而且千位数字不能是0。所以可以用广搜,枚举各个数位上的数字,满足要求的数就加入队列,直到变换成功。因为是广搜,所以一定能保证次数最少。

    AC代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    using namespace std;
    
    int n, m;
    const int N = 1e4 + 100;
    int vis[N];
    struct node
    {
        int x, step;
    };
    queue<node> Q;
    
    bool judge_prime(int x) //判断素数
    {
        if(x == 0 || x == 1)
            return false;
        else if(x == 2 || x == 3)
            return true;
        else
        {
            for(int i = 2; i <= (int)sqrt(x); i++)
                if(x % i == 0)
                    return false;
            return true;
        }
    }
    
    void BFS()
    {
        int X, STEP, i;
        while(!Q.empty())
        {
            node tmp;
            tmp = Q.front();
            Q.pop();
            X = tmp.x;
            STEP = tmp.step;
            if(X == m)
            {
                printf("%d
    ",STEP);
                return ;
            }
            for(i = 1; i <= 9; i += 2) //个位
            {
                int s = X / 10 * 10 + i;
                if(s != X && !vis[s] && judge_prime(s))
                {
                    vis[s] = 1;
                    node temp;
                    temp.x = s;
                    temp.step = STEP + 1;
                    Q.push(temp);
                }
            }
            for(i = 0; i <= 9; i++) //十位
            {
                int s = X / 100 * 100 + i * 10 + X % 10;
                if(s != X && !vis[s] && judge_prime(s))
                {
                    vis[s] = 1;
                    node temp;
                    temp.x = s;
                    temp.step = STEP + 1;
                    Q.push(temp);
                }
            }
            for(i = 0; i <= 9; i++) //百位
            {
                int s = X / 1000 * 1000 + i * 100 + X % 100;
                if(s != X && !vis[s] && judge_prime(s))
                {
                    vis[s] = 1;
                    node temp;
                    temp.x = s;
                    temp.step = STEP + 1;
                    Q.push(temp);
                }
            }
            for(i = 1; i <= 9; i++) //千位
            {
                int s = i * 1000 + X % 1000;
                if(s != X && !vis[s] && judge_prime(s))
                {
                    vis[s] = 1;
                    node temp;
                    temp.x = s;
                    temp.step = STEP + 1;
                    Q.push(temp);
                }
            }
        }
        printf("Impossible
    ");
        return ;
    }
    
    int main()
    {
        int t, i;
        scanf("%d",&t);
        while(t--)
        {
            while(!Q.empty()) Q.pop();
            scanf("%d%d",&n,&m);
            memset(vis,0,sizeof(vis));
            vis[n] = 1;
            node tmp;
            tmp.x = n;
            tmp.step = 0;
            Q.push(tmp);
            BFS();
        }
        return 0;
    }
    View Code

    (2)埃氏的优化,依拉筛法

    我们可以知道,任意一个正整数k,若k≥2,则k可以表示成若干个质数相乘的形式。Eratosthenes筛法中,在枚举k的每一个质因子时,我们都计算了一次k,从而造成了冗余。因此在改进算法中,只利用k的最小质因子去计算一次k。 
    与Eratosthenes筛法不同的是,对于外层枚举i,无论i是质数,还是是合数,我们都会用i的倍数去筛。但在枚举的时候,我们只枚举i的质数倍。比如2i,3i,5i,…,而不去枚举4i,6i…,原因我们后面会讲到。

    此外,在从小到大依次枚举质数p来计算i的倍数时,我们还需要检查i是否能够整除p。若i能够整除p,则停止枚举。

    利用该算法,可以保证每个合数只会被枚举到一次。

    综上,Eular筛法可以保证每个合数只会被枚举到一次,时间复杂度为O(n)。当N越大时,其相对于Eratosthenes筛法的优势也就越明显。

    AC代码:

    int primelist[N], primecount = 0;
    bool isprime[N];
    void eular(int n){
        int i, j;
        for (i = 0; i <= n; i++){
            isprime[i] = true;
        }
        isprime[0] = isprime[1] = false;
        for (i = 2; i <= n; i++){
            if (isprime[i]){
                primelist[primecount++] = i;
            }
            for (j = 0; j < primecount; j++){
                if (i*primelist[j] > n){
                    break;
                }
                isprime[i*primelist[j]] = false;
                if (i%primelist[j]==0){
                    break;
                }
            }
        }
    }
    View Code

    (3)大数据打表法

    #include<stdio.h>
    #include<math.h>
    int p[1000000],a[10000001],t=0;
    int prime(int n)
    {
        int i,q;
        q=(int)sqrt(n);
        for(i=0;p[i]<=q&&t;i++)
            if(n%p[i]==0)return 0;
        return 1;
    }
    void main()
    {
        int n,i;
        scanf("%d",&n);
        for(i=2;i<=n;i++)
            if(prime(i))p[t++]=i;
        for(i=0;i<t;i++)
            printf("%d%c",p[i],i<t-1?' ':'/n');
    }
    View Code

    (4)神奇万能法

    适合单数据,也适合超大数据

    #include<stdio.h>
    #include<math.h>
    int p[8]={4,2,4,2,4,6,2,6};
    int prime(int n)
    {
        int i=7,j,q;
        if(n==1)return 0;
        if(n==2||n==5||n==3)return 1;
        if(n%2==0||n%3==0||n%5==0)return 0;
        q=(int)sqrt(n);
        for(;i<=q;){
            for(j=0;j<8;j++){
                if(n%i==0)return 0;
                i+=p[j];
            }
            if(n%i==0)return 0;
        }
        return 1;
    }
    void main()
    {
        int n;
        scanf("%d",&n);
        if(prime(n))puts("Yes");
        else puts("No");
    }
    View Code

     
    大素数测试+求最小素因子+最大素因子(模版)

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <time.h>
    #define MAXN 10
    #define C 16381
    using namespace std;
    typedef __int64 I64;
     
    I64 min;
     
    I64 multi(I64 a, I64 b, I64 n){
        I64 tmp = a % n, s = 0;
        while(b){
            if(b & 1) s = (s + tmp) % n;
            tmp = (tmp + tmp) % n;
            b >>= 1;
        }
        return s;
    }
     
    I64 Pow(I64 a, I64 b, I64 n){
        I64 tmp = a % n, s = 1;
        while(b){
            if(b & 1) s = multi(s, tmp, n);
            tmp = multi(tmp, tmp, n);
            b >>= 1;
        }
        return s;
    }
     
    int witness(I64 a, I64 n){
        I64 u = n - 1, t = 0, i, x, y;
        while(!(u & 1))    u >>= 1, t ++;
        x = Pow(a, u, n);
        for(i = 1; i <= t; i ++){
            y = multi(x, x, n);
            if(y == 1 && x != 1 && x != n -1) return 1;
            x = y;
        }
        if(x != 1) return 1;
        return 0;
    }
     
    int test(I64 n){
        I64 a;
        int i;
        if(n == 2) return 1;
        if(n < 2 || !(n & 1)) return 0;
        srand((I64)time(0));
        for(i = 0; i < MAXN; i ++){
            a = ((I64) rand()) % (n - 2) + 2;
            if(witness(a, n)) return 0;
        }
        return 1;
    }
     
    I64 gcd(I64 a, I64 b){
        return b ? gcd(b, a % b) : a;
    }
     
    I64 pollard_rho(I64 n, I64 c){
        I64 x, y, d, i = 1, k = 2;
        srand((I64)time(0));
        x = ((I64) rand()) % (n - 1) + 1;
        y = x;
        while(1){
            i ++;
            x = (multi(x, x, n) + c) % n;
            d = gcd(y - x + n, n);
            if(d != 1 && d != n) return d;
            if(y == x) return n;
            if(i == k) y = x, k <<= 1;
        }
    }
     
    void find(I64 n, I64 c){
        I64 r;
        if(n <= 1) return;
        if(test(n)){
            if(min > n) min = n;
            return;
        }
        r = pollard_rho(n, c--);
        find(n / r, c);
        find(r, c);
    }
     
    I64 MaxPrimeFactor(I64 n)
    {
        if(test(n))
        return n;
        
        I64 k=-1,g;
        min=n;
        find(n,C);
        
        g=MaxPrimeFactor(min);
        k=g>k?g:k;
        
        g=MaxPrimeFactor(n/min);
        k=g>k?g:k;
        return k;
    }
    int main(){
        I64 n;
            while(~scanf("%I64d", &n))
            {
                // if(test(n)){                //test(n)测试n是不是素数
                // printf("Prime
    ");
                // continue;
                // }
                // min = n;                   //min表示n的最小素因子
                // find(n, C);                //找出n的最小素因子
                // printf("%I64d
    ",min);
                printf("%I64d
    ",MaxPrimeFactor(n));//求n的最大素因子
            }
        return 0;
    }
    View Code
  • 相关阅读:
    关于C的struct结构的几个常见疑问。
    NAT类型
    Linux oops stack 分析
    关于pci_dev的定义
    还是动态添加控件 触发事件
    页面编译模型
    MDX 销售额与上月比较
    C语言的词法语法分析lex&yacc 经典收藏
    interrupt storm
    js获取mac地址
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/8981944.html
Copyright © 2011-2022 走看看