判断素数的方法

题目如下:

链接:筛选法求素数__牛客网
来源:牛客网

用筛选法求n以内的素数。筛选法求解过程为:将2~n之间的正整数放在数组内存储,将数组中2之后的所有能被2整除的数清0,再将3之后的所有能被3整除的数清0 ,以此类推,直到n为止。数组中不为0 的数即为素数。

一开始没看明白题目意思,以为只需要满足不是2或者3的倍数就可以了,然后发现出错了,后来才发现搞错掉了

然后我就查了下判断素数的方法,有如下几个,但不止这几个:1.AKS算法——公认最优的算法(但实际应用中不常见)        2.Miller—Rabbin算法(基于费马小定理的扩展)        3.试除法(优化6倍法)        4.筛选法

1.AKS算法
直说吧,没看懂,太复杂,我也不会,但从GPT那里获得了c++的简易模板

代码如下:
 

#include <iostream>
#include <cmath>
using namespace std;
 
typedef long long ll;
 
// 求最大公约数的辗转相除法
ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}
 
// 快速幂算法
ll binpow(ll a, ll b, ll m) {
    ll res = 1;
    a %= m;
    while (b > 0) {
        if (b & 1) {
            res = res * a % m;
        }
        a = a * a % m;
        b >>= 1;
    }
    return res;
}
 
// 判断一个数是否为素数
bool is_prime(ll n) {
    if (n <= 1) {
        return false;
    }
    if (n <= 3) {
        return true;
    }
    if (n % 2 == 0 || n % 3 == 0) {
        return false;
    }
    ll r = sqrt(n);
    for (ll i = 5; i <= r; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) {
            return false;
        }
    }
    return true;
}
 
// 判断n是否是a的幂
bool is_power(ll n) {
    if (n <= 1) {
        return true;
    }
    ll r = sqrt(n);
    for (ll a = 2; a <= r; ++a) {
        ll p = a;
        while (p <= n) {
            p *= a;
            if (p == n) {
                return true;
            }
        }
    }
    return false;
}
 
// AKS算法判断n是否为素数
bool AKS(ll n) {
    // 如果n是a的幂,则n不是素数
    if (is_power(n)) {
        return false;
    }
    // 寻找r,满足n^r-1 = (n-1)q,其中q为素数
    ll r = 2;
    while (r <= sqrt(n)) {
        if (n % r == 0) {
            return false;
        }
        ll phi_r = r - 1;
        if (gcd(n, r) == 1) {
            bool is_valid = true;
            for (ll a = 2; a <= sqrt(phi_r) && is_valid; ++a) {
                if (gcd(a, r) == 1) {
                    is_valid = binpow(a, phi_r, n) != 1;
                }
            }
            if (is_valid) {
                ll q = (n - 1) / r;
                if (gcd(q, r) == 1 && binpow(n, q, r) == 1) {
                    return true;
                }
            }
        }
        ++r;
    }
    return false;
}
 
int main() {
    ll n;
    cin >> n;
    if (AKS(n)) {
        cout << n << " is prime" << endl;
    } else {
        cout << n << " is not prime" << endl;
    }
    return 0;
}

2.Miller—Rabbin算法

原理:

    1如果要判断的数n等于2或3,则判定为素数。

    2如果n可以以表示为a^b的形式,则判定n为合数。

    3如果n不是奇数,则判定n为合数。

   4计算r使得r是最小的满足下列不等式之一的整数。

    5对所有满足1 < a ≤ r的整数a,判断是否满足条件之一:

(i) a^n ≡ a mod n (ii) 对于所有0 < k < n,有(a^k) mod (x^r - 1, n) = 1

如果满足上述条件,则判定n为素数,否则n为合数。

3.试除法(优化6倍法)

​
bool is_prime(int n) {
    if (n <= 1) return false;  // 1 不是素数
    if (n <= 3) return true;   // 2 和 3 是素数
    if (n % 2 == 0 || n % 3 == 0) return false;  // 排除掉 2 和 3 的倍数
 
    int max_divisor = sqrt(n); //求待判断数开方数
    for (int i = 5; i <= max_divisor; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) {
            return false;
        }
    }
    return true;
}
 
​

试除法(也称质因数分解法)是一种用来判断一个数是否为素数的算法。它的基本原理是将要判断的数 n 依次除以 2 到 sqrt{n} 之间的每个整数,如果都不能整除,则 n 是素数。如果存在能整除 n 的整数,则 n 不是素数。

在优化的试除法中,我们可以先判断 n 是否为 2 或 3,然后只对 6k±1 的形式进行试除,这样能够减少试除的次数,提高算法效率。具体实现中,我们只需要判断 6k±1 ≤ √n  是否成立即可。

需要注意的是,如果 n 为合数,它必定存在小于 sqrt{n} 的质因子,因此只需要试除 2 到 sqrt{n} 之间的数即可,不需要试除所有的数
4.筛选法

#include <iostream>
#include <vector>
 
using namespace std;
 
vector<int> get_primes(int n) {
    vector<int> primes;
    vector<bool> is_prime(n + 1, true); // 初始化所有数为素数
 
    is_prime[0] = is_prime[1] = false; // 排除0和1不是素数的情况
 
    // 从2开始筛选,将所有的倍数标记为非素数
    for (int i = 2; i * i <= n; i++) {
        if (is_prime[i]) {
            for (int j = i * i; j <= n; j += i) {
                is_prime[j] = false;
            }
        }
    }
 
    // 收集所有的素数
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) {
            primes.push_back(i);
        }
    }
 
    return primes;
}
 
int main() {
    int n;
    cin >> n;
 
    vector<int> primes = get_primes(n);
 
    for (int prime : primes) {
        cout << prime << " ";
    }
    cout << endl;
 
    return 0;
}

它的基本思想是先假设所有数都是素数,然后从2开始,将其倍数标记为合数,最终剩下的未被标记的数即为素数。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值