素数判定方法详解:从基础试除法到优化策略

news2025/3/19 6:36:39

        素数是只能被1和自身整除的正整数。素数的判定是数论中的基础问题,也是算法竞赛中的常见考点。


一、知识点

  1. 素数的定义
    素数(质数)是大于1的自然数,且只能被1和自身整除。

  2. 试除法
    通过遍历从2到sqrt(n)​的所有整数,判断是否能整除n。如果能整除,则n不是素数。

  3. 试除法的优化

    • 优化1:将试除范围从[2, n-1]缩小到[2, sqrt(n)​]。

    • 优化2:仅用[2, sqrt(n)​]内的素数试除,避免用合数试除。

  4. 时间复杂度

    • 未优化的试除法:O(n)。

    • 优化后的试除法:O(sqrt(n))。


二、试除法及其优化

1. 基础试除法

  • 原理:遍历从2到sqrt(n)​的所有整数,检查是否能整除n。

  • 代码实现

    bool isPrime(long long n) {
        if (n <= 1) return false; // 1不是素数
        for (long long i = 2; i <= sqrt(n); i++) {
            if (n % i == 0) return false; // 能整除,不是素数
        }
        return true; // 是素数
    }
  • 说明

    • sqrt(n):只需遍历到sqrt(n)​​,因为如果n有大于sqrt(n)​的因子,必然有小于sqrt(n)​的因子。

    • 时间复杂度:O(sqrt(n)​)。

2. 试除法的第一次优化

  • 原理:仅用[2, sqrt(n)​​]内的素数试除,避免用合数试除。

  • 实现步骤

    1. 预先生成[2, sqrt(n)​]内的所有素数(如用筛法)。

    2. 用这些素数试除n。

  • 代码实现

    bool isPrimeOptimized(long long n, const vector<long long>& primes) {
        if (n <= 1) return false; // 1不是素数
        for (long long p : primes) {
            if (p * p > n) break; // 超过sqrt(n),停止
            if (n % p == 0) return false; // 能整除,不是素数
        }
        return true; // 是素数
    }
  • 说明

    • primes:预先生成的素数列表(如用埃氏筛法生成)。

    • 时间复杂度:O(sqrt(n)​/log⁡n),因为素数密度约为log⁡n。

3. 试除法的第二次优化

  • 原理:结合筛法,动态生成素数列表,避免预先生成。

  • 实现步骤

    1. 使用筛法(如埃氏筛法)动态生成[2, sqrt(n)​​]内的素数。

    2. 用这些素数试除n。

  • 代码实现

    vector<long long> generatePrimes(long long limit) {
        vector<bool> isPrime(limit + 1, true);
        vector<long long> primes;
        for (long long i = 2; i <= limit; i++) {
            if (isPrime[i]) {
                primes.push_back(i);
                for (long long j = i * i; j <= limit; j += i) {
                    isPrime[j] = false;
                }
            }
        }
        return primes;
    }
    
    bool isPrimeOptimized2(long long n) {
        if (n <= 1) return false; // 1不是素数
        long long limit = sqrt(n);
        vector<long long> primes = generatePrimes(limit);
        return isPrimeOptimized(n, primes);
    }
  • 说明

    • generatePrimes:生成[2, sqrt(n)​​]内的素数列表。

    • 时间复杂度:O(sqrt(n) ​log⁡ log⁡n)(筛法复杂度)。


三、代码说明

  1. 基础试除法

    • 适用于小规模数据(n≤10^12)。

    • 实现简单,但效率较低。

  2. 第一次优化

    • 通过预先生成素数列表,减少试除次数。

    • 适用于需要多次判断素数的场景。

  3. 第二次优化

    • 动态生成素数列表,避免预先生成。

    • 适用于单次判断素数且n较大的场景。

四、例题解析

P1036 [NOIP 2002 普及组] 选数 - 洛谷 

算法代码: 

#include<bits/stdc++.h>  // 包含所有标准库头文件
using namespace std;     // 使用标准命名空间

int n, k;                // n: 数组长度, k: 需要选择的元素个数
int a[20];               // 存储输入的数组
int ans;                 // 记录满足条件的组合数

// 判断一个数是否为素数
bool is_prime(int s) {
    if (s <= 1) {        // 1及以下的数不是素数
        return false;
    }
    for (int i = 2; i <= sqrt(s); i++) {  // 遍历2到sqrt(s)
        if (s % i == 0) {  // 如果s能被i整除,说明s不是素数
            return false;
        }
    }
    return true;         // 否则s是素数
}

// 深度优先搜索(DFS)函数
// cnt: 当前已选择的元素个数
// sum: 当前已选择元素的和
// p: 当前选择的起始位置
void dfs(int cnt, int sum, int p) {
    if (cnt == k) {      // 如果已经选择了k个元素
        if (is_prime(sum)) {  // 判断这些元素的和是否为素数
            ans++;       // 如果是素数,答案加1
        }
        return;         // 返回上一层递归
    }
    for (int i = p; i < n; i++) {  // 从位置p开始选择元素
        dfs(cnt + 1, sum + a[i], i + 1);  // 递归选择下一个元素
    }
}

int main() {
    cin >> n >> k;       // 输入数组长度n和需要选择的元素个数k
    for (int i = 0; i < n; i++) {  // 输入数组元素
        cin >> a[i];
    }
    dfs(0, 0, 0);        // 调用DFS函数,初始状态:已选0个元素,和为0,起始位置为0
    cout << ans;         // 输出满足条件的组合数
    return 0;            // 程序结束
}

1. 问题描述

  • 输入:一个长度为n的数组a,以及一个整数k

  • 目标:从数组a中选择k个元素,使得这些元素的和为素数。统计所有满足条件的组合数。


2. 设计思路

(1)核心问题分解

  • 子问题1:如何判断一个数是否为素数?

  • 子问题2:如何从数组中选择k个元素,并计算它们的和?

  • 子问题3:如何统计所有满足条件的组合数?

(2)解决子问题1:素数判断

  • 方法:使用试除法。

    • 遍历从2到sqrt(n)​的所有整数,检查是否能整除n

    • 如果能整除,则n不是素数;否则,n是素数。

  • 代码实现

    bool is_prime(int s) {
        if (s <= 1) return false; // 1及以下的数不是素数
        for (int i = 2; i <= sqrt(s); i++) {
            if (s % i == 0) return false; // 能整除,不是素数
        }
        return true; // 是素数
    }

(3)解决子问题2:选择k个元素并计算和

  • 方法:使用深度优先搜索(DFS)遍历所有可能的组合。

    • 从数组中选择k个元素,确保不重复选择。

    • 在DFS过程中,记录当前已选择的元素个数、当前和以及选择的起始位置。

  • 代码实现

    void dfs(int cnt, int sum, int p) {
        if (cnt == k) { // 已选择k个元素
            if (is_prime(sum)) ans++; // 如果和为素数,答案加1
            return;
        }
        for (int i = p; i < n; i++) { // 从位置p开始选择
            dfs(cnt + 1, sum + a[i], i + 1); // 递归选择下一个元素
        }
    }

(4)解决子问题3:统计满足条件的组合数

  • 方法:在DFS过程中,每当找到一个满足条件的组合(和为素数),就将计数器ans加1。

  • 代码实现

    int ans = 0; // 初始化计数器
    dfs(0, 0, 0); // 调用DFS函数
    cout << ans; // 输出结果

3. 代码实现步骤

(1)输入部分
  • 读取数组长度n和需要选择的元素个数k

  • 读取数组a的元素。

    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
(2)DFS函数
  • 参数说明

    • cnt:当前已选择的元素个数。

    • sum:当前已选择元素的和。

    • p:当前选择的起始位置(避免重复选择)。

  • 递归终止条件

    • cnt == k时,检查sum是否为素数。如果是,则ans++

  • 递归过程

    • 从位置p开始,依次选择数组中的元素,并递归调用DFS。

      void dfs(int cnt, int sum, int p) {
          if (cnt == k) {
              if (is_prime(sum)) ans++;
              return;
          }
          for (int i = p; i < n; i++) {
              dfs(cnt + 1, sum + a[i], i + 1);
          }
      }
(3)输出结果
  • 调用DFS函数后,输出满足条件的组合数ans

    dfs(0, 0, 0);
    cout << ans;

4. 时间复杂度分析

  • is_prime函数:O(sqrt(n))。

  • DFS函数:O(C(n,k)),其中C(n,k)是从n个元素中选择k个元素的组合数。

  • 总时间复杂度:O(C(n,k)×sqrt(n))。


5. 优化建议

  • 剪枝优化:在DFS过程中,如果当前和sum已经大于某个阈值,可以提前终止递归。

  • 素数预处理:如果需要多次判断素数,可以预先生成一个素数表,减少重复计算。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2317636.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BFS,DFS带图详解+蓝桥杯算法题+经典例题

1.BFS和DFS的定义与实现方式 1.1 深度优先搜索&#xff08;DFS&#xff09; 基本概念&#xff1a;DFS 是一种用于遍历或搜索图或树的算法。它从起始节点开始&#xff0c;沿着一条路径尽可能深地探索下去&#xff0c;直到无法继续或者达到目标节点&#xff0c;然后回溯到上一个…

「清华大学、北京大学」DeepSeek 课件PPT专栏

你要的 这里都打包好啦&#xff0c;快快收藏起来&#xff01; 名称 链接 团队简介 类型 DeepSeek——从入门到精通 1️⃣ DeepSeek从入门到精通「清华团队」 清华大学新闻与传播学院 新媒体研究中心 元宇宙文化实验室 PPT课件 DeepSeek如何赋能职场应用? ——从提示语…

如何在 Github 上获得 1000 star?

作为程序员&#xff0c;Github 是第一个绕不开的网站。我们每天都在上面享受着开源带来的便利&#xff0c;我相信很多同学也想自己做一个开源项目&#xff0c;从而获得大家的关注。然而&#xff0c;理想很丰满&#xff0c;现实却是开发了很久的项目仍然无人问津。 最近&#x…

on-policy对比off-policy

目录 持续更新。。。 on-policy与off-policy的定义 Q-learning属于on-policy算法还是off-policy算法&#xff1f; 为什么off-policy适用于从离线经验或多种探索策略中学习&#xff0c;明明 On-policy 也可以基于探索学习的啊&#xff1f; 重要性权重方法 off-policy方法可…

基于SpringBoot+Vue的幼儿园管理系统+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、教师、普通用户功能模块&#xff1a;用户管理、教师管理、班级管理、幼儿信息管理、会议记录管理、待办事项、职工考核、请假信息、缴费信息、体检管理、资源管理、原料管理、菜品信息管理等技术选型&#xff1a;SpringBoot&#xff0…

案例5_3: 6位数码管静态显示

文章目录 文章介绍效果图仿真图复习知识&#xff1a;代码思考 文章介绍 第5章 学习数码管&#xff0c;使用6位数码管进行静态显示 效果图 仿真图 新建一个干净的5_3文件夹&#xff0c;用于存放新画的仿真图 除单片机最小系统外&#xff0c;新增3个元器件&#xff0c;分别是&…

Profinet转Modbus RTU/TCP以太网通讯处理器

Profinet转Modbus RTU/TCP以太网通讯处理器 在当今的工业自动化领域&#xff0c;各种通讯协议和标准层出不穷。 其中&#xff0c;Profinet和Modbus作为两种广泛应用的通讯协议&#xff0c;分别在不同的应用场景中发挥着重要作用。 然而&#xff0c;当需要将这两种协议进行转换…

3倍训练速度+40%显存节省!Mamba+Transformer 仅用一半时间,性能提升80%!

在人工智能领域&#xff0c;Mamba与Transformer的结合正在成为研究热点&#xff0c;为自然语言处理和多模态任务带来新的突破。 最新研究表明&#xff0c;通过将Mamba架构与Transformer的强大编码能力相结合&#xff0c;模型在处理复杂的多模态数据时的效率提升了50%&#xff…

春秋云境刷题1

CVE-2022-29464 靶标介绍&#xff1a; WSO2文件上传漏洞&#xff08;CVE-2022-29464&#xff09;是Orange Tsai发现的WSO2上的严重漏洞。该漏洞是一种未经身份验证的无限制任意文件上传&#xff0c;允许未经身份验证的攻击者通过上传恶意JSP文件在WSO2服务器上获得RCE。 Git…

台式机电脑组装---电源

台式机电脑组装—电源 22 33 主板供电是聚集了12V&#xff0c;5V,3.3V的24pin CPU供电的话主要是12V的44pin供电 44pin合并之后&#xff0c;就是8pin 55 SATA硬盘会使用饼io口取电&#xff0c;从电源获取12v,5v,3.3v的电 33

10-BST(二叉树)-建立二叉搜索树,并进行前中后遍历

题目 来源 3540. 二叉搜索树 - AcWing题库 思路 建立二叉搜索树&#xff08;注意传参时用到了引用&#xff0c;可以直接对root进行修改&#xff09;&#xff0c;同时进行递归遍历&#xff1b;遍历可以分前中后三种写&#xff0c;也可以用标志来代替合在一起。其余详见代码。…

蓝桥杯备考:贪心问题之淘淘摘苹果

这是淘淘摘苹果普通版&#xff0c;很可爱的一道题&#xff0c;我们不多陈述&#xff0c;直接上代码 #include <iostream> using namespace std; const int N 15; int a[N]; int main() {for(int i 1;i<10;i){cin >> a[i];}int x;cin >> x;x30;int cnt …

VSTO(C#)Excel开发 系列目录 含源码发布

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

Git使用和原理(3)

1.远程操作 1.1分布式版本控制系统 我们⽬前所说的所有内容&#xff08;⼯作区&#xff0c;暂存区&#xff0c;版本库等等&#xff09;&#xff0c;都是在本地&#xff01;也就是在你的笔记本或者 计算机上。⽽我们的 Git 其实是分布式版本控制系统&#xff01;什么意思呢&a…

博客图床 VsCode + PigGo + 阿里云OSS

关键字 写博客&#xff0c;图床&#xff0c;VsCode&#xff0c;PigGo&#xff0c;阿里云OSS 背景环境 我想把我在本地写的markdown文档直接搬到CSDN上和博客园上&#xff0c;但是图片上传遇到了问题。我需要手动到不同平台上传文件&#xff0c;非常耗费时间和经历。 为了解决…

C++之list类及模拟实现

目录 list的介绍 list的模拟实现 定义节点 有关遍历的重载运算符 list的操作实现 &#xff08;1&#xff09;构造函数 (2)拷贝构造函数 &#xff08;3&#xff09;赋值运算符重载函数 &#xff08;4&#xff09;析构函数和clear成员函数 &#xff08;5&#xff09;尾…

SwinTransformer 改进:添加DoubleAttention模块提升上下文语义提取能力

目录 1. DoubleAttention模块 2. SwinTransformer + DoubleAttention 3. 完整代码 Tips:融入模块后的网络经过测试,可以直接使用,设置好输入和输出的图片维度即可 1. DoubleAttention模块 DoubleAttention 是一种用于计算机视觉任务的注意力机制,旨在通过双重注意力机制…

MacBook部署达梦V8手记

背景 使用Java SpringBootDM开发Web应用&#xff0c;框架有License&#xff0c;OSX加载dll失败&#xff0c;安装了Windows 11&#xff0c;只有一个C盘&#xff0c;达梦安装后因为C盘权限问题&#xff0c;创建数据库失败&#xff0c;遂采用Docker容器方式部署。 下载介质 官网在…

外贸 B2B 平台没落?多语言批发系统正在崛起

近年来&#xff0c;全球外贸行业正在发生快速变化&#xff0c;传统的 B2B 平台正面临越来越多的挑战&#xff0c;尤其是在面对新兴的多语言批发系统时。这种变化不仅影响了供应商和买家之间的交易方式&#xff0c;也正在推动外贸行业的数字化升级和转型。今天&#xff0c;让我们…

[spring] Spring JPA - Hibernate 多表联查 1

[spring] Spring JPA - Hibernate 多表联查 之前在 [spring] spring jpa - hibernate 名词解释&配置 和 [spring] spring jpa - hibernate CRUD 简单的学习了一下怎么使用 Hibernate 实现 CRUD 操作&#xff0c;不过涉及到的部分都是逻辑上比较简单的实现——只在一张表上…