当前位置: 首页 > news >正文

【算法设计-枚举、分治】素数、约数、质因数分解

文章目录

    • 1. 素数判定
    • 2. 素数筛选法
    • 3. 质因数分解
    • 4. 求一个数的约数
    • 5. 求两个数的最大公约数(GCD)
    • 6. 求两个数的最小公倍数(LCM)

1. 素数判定

判定从 2 到sqrt(n)依次能否把 n 整除,若存在可以整除的数则说明 n 不是素数,若都不可以整除则说明 n 是素数。

注意:2 是特殊的素数。

为什么到sqrt(n)就可以了呢?请观察下面两个合数的例子:

30 分解为两个因数相乘:

  • 2 x 15
  • 3 x 10
  • 5 x 6
  • 6 x 5
  • 10 x 3
  • 15 x 2

36 分解为两个因数相乘:

  • 2 x 18
  • 3 x 12
  • 4 x 9
  • 6 x 6
  • 9 x 4
  • 12 x 3
  • 18 x 2

发现当越过sqrt(n)后,得到的两个因数与sqrt(n)前相同(只是位置对调了而已),因此没有必要对sqrt(n)后的数进行试除。

#include <cstdio>
#include <cmath>
using namespace std;bool isPrime (int x){if (x == 2)return true;else{int bound = sqrt(x);for (int i = 2; i <= bound; i++)if (x % i == 0) return false;}return true;
}int main(){int n;while (scanf("%d", &n) != EOF){bool flag = isPrime(n);if (flag)printf("Yes\n");elseprintf("No\n");}return 0;
}

2. 素数筛选法

原理:

  • 2 是素数,把 2 后面所有能被 2 整除的数都划去;
  • 2 后面第一个没划去的数是 3,把 3 留下,3 后面所有能被 3 整除的数都划去;
  • 3 后面第一个没划去的数是 5,把 5 留下,5 后面所有能被 5 整除的数都划去;
  • 5 后面第一个没划去的数是 7,把 7 留下,7 后面所有能被 7 整除的数都划去;

注意:每次划去当前质数的倍数时,可能存在某些数被重复筛选的情况,如 8 既被 2 又被 4 筛选。在枚举筛选的时候可以进行剪枝,当 i 为素数时,注意到i * k (k < i)必定已经在求得 k 的某个素数因子时被标记过,因此可以从i * i开始。

#include <math.h>
#include <stdio.h>
#include <string.h>#define MAX 10000bool isPrime[MAX+1];int main(){int n;scanf("%d", &n);memset(isPrime, true, sizeof(isPrime));  // memset函数包含于string.h头文件中 for (int i = 2; i <= sqrt(n); i++){if (isPrime[i]){	// 发现是素数,下面将素数的倍数都标记为非素数for (int j = i * i; j < n; j += i)  // i*k(k<i)必定已经在求得k的某个素数因子时被标记过,因此从i*i开始 isPrime[j] = false;}}for (int i = 2; i < n; i++)if (isPrime[i]) printf("%d ", i);return 0;
}

3. 质因数分解

输入:

994

输出:

2 7 71

代码:

#include <math.h>
#include <stdio.h>
#include <string.h>#define MAX 10000bool isPrime[MAX+1];int main(){int n;scanf("%d", &n);memset(isPrime, true, sizeof(isPrime));  // memset函数包含于string.h头文件中 int bound = sqrt(n);// 标记素数 for (int i = 2; i <= bound; i++){if (isPrime[i]){	// 发现是素数,下面将素数的倍数都标记为非素数for (int j = i * i; j < n; j += i)  // i*k(k<i)必定已经在求得k的某个素数因子时被标记过,因此从i*i开始 isPrime[j] = false;}}// 分解质因数for (int i = 2; i <= bound; i++){if (isPrime[i]){  // 如果是质数,则开始试除 while (n % i == 0){		// 若发现能整除,则继续使用这个质数除下去 n = n / i;printf("%d ", i);}}} if (n > 1)	// 若除完后,结果不是1,说明剩下来的是质数 printf("%d", n);return 0;
}

4. 求一个数的约数

在自然数(0和正整数)的范围内,

4的正约数有:1、2、4。

6的正约数有:1、2、3、6。

10的正约数有:1、2、5、10。

12的正约数有:1、2、3、4、6、12。

15的正约数有:1、3、5、15。

18的正约数有:1、2、3、6、9、18。

20的正约数有:1、2、4、5、10、20。

注意:一个数的约数必然包括1及其本身。

#include <cstdio>
#include <cmath>
using namespace std;int main(){int n;while (scanf("%d", &n) != EOF){for (int i = 1; i <= sqrt(n); i++){if (n % i == 0){printf("%d %d ", i, n / i);}}printf("\n");}return 0;
}

5. 求两个数的最大公约数(GCD)

辗转相除法:两个整数的最大公约数等于其中较小的数和两数相除的余数的最大公约数,即gcd(a,b) = gcd(b, a mod b)

基本思想:分治。

原理:若整数 g 为 a、b 的最大公约数,则有:

a = g x l(1)

b = g x m(2)

a、b 又可以表示为:

a = b x k + r(即a / b = k···r)(3)

把(1)(2)代入到(3):

g x l = g x m x k + r,即r = g x (l - m x k)

注意到r = a mod b,因此a mod b = g x (l - m x k)(4)

联合(2)(4),这样问题变为了求 b 和 a mod b 的最大公约数:

b = g x m(2)

a mod b = g x (l - m x k)(5)

递归写法:

// 辗转相除法求最大公约数(12和18的最大公约数:6) 
int gcd (int a, int b){if (b == 0)return a;elsereturn gcd(b, a % b);
}

非递归写法:

// 辗转相除法求最大公约数(12和18的最大公约数:6) 
int gcd (int a, int b){while (b != 0){int rem = a % b;a = b;b = rem;}return a;
}

6. 求两个数的最小公倍数(LCM)

// 求最小公倍数(12和18的最小公倍数:36)
int lcm (int a, int b){return a * b / gcd(a, b);
}
http://www.lryc.cn/news/28705.html

相关文章:

  • 【第十四届蓝桥杯】第三期模拟赛B组C++题解(待修正+持续更新-ing)
  • 线程池和ThreadLocal详解
  • [深入理解SSD系列综述 1.7] SSD固态存储市场发展分析与预测_固态存储技术发展方向(2022to2023)
  • 【2021.12.25】ctf逆向中常见加密算法和编码识别
  • 【数据结构初阶】堆排序
  • Day5: platformDriver-1
  • 开发手册——一、编程规约_7.控制语句
  • python每日学9 : windows上配置gitee的远程仓库,git的初步使用
  • 精确率与召回率,ROC曲线与PR曲线
  • 现代操作系统——Linux架构与学习
  • 中文代码82
  • 顺序表(一篇带你掌握顺序表)
  • 【SpringCloud】SpringCloud教程之Feign实战
  • 嵌入式linux必备内存泄露检测神器
  • 设计模式之行为型模式
  • 解密 三岁的三岁到底为什么叫做三岁?
  • id选择器
  • 《科技之巅3》读书笔记
  • 18.用于大型程序的工具
  • mysql一主键uuid和自增的选择
  • 【EDA工具使用】——VCS和Verdi的联合仿真的简单使用
  • 【Java学习笔记】4.Java 对象和类
  • 39. 实战:基于api接口实现视频解析播放(32接口,窗口化操作,可导出exe,附源码)
  • 基于灵动 MM32 微控制器的便携式血氧仪方案
  • 2022秋-2023-中科大-数字图像分析-期末考试试卷回忆版
  • 【matplotlib】条形图及垂线显示小技巧 |一些有用参考帖子收集
  • Go的bytes.Buffer
  • k8s学习之路 | Day19 k8s 工作负载 Deployment(上)
  • php宝塔搭建部署实战六零导航页LyLme_Spage源码
  • SpringBoot (三) 整合数据库访问 jdbcTemplate、MyBatis