首页 > 编程语言 >【算法设计-枚举、分治】素数、约数、质因数分解

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

时间:2023-03-04 15:46:02浏览次数:45  
标签:约数 12 因数分解 int 素数 枚举 include 最大公约数

目录

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");
		else
			printf("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 10000

bool 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 10000

bool 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;
    else
        return 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);
}

标签:约数,12,因数分解,int,素数,枚举,include,最大公约数
From: https://www.cnblogs.com/Mount256/p/17178405.html

相关文章

  • 关于最大公约数-最大公因数的原理与表示方法
    在数学中,有两个名词经常会被听到,最大公因数,最大公约数刚开始还以为他们有什么区别呢,后来查询了一下,其实都是一个意思,只是叫法不一样接下来说一下最大公因数的定义 理......
  • 判断某个值是否存在指定枚举类中
    publicenumPayRecordPayWayEnum{BALANCE(1,"余额"),//1:余额ALI(2,"支付宝"),//2:支付宝WECHAT(3,"微信"),//3:......
  • P1403 约数研究
    题目传送门约数研究题目描述科学家们在Samuel星球上的探险得到了丰富的能源储备,这使得空间站中大型计算机“SamuelII”的长时间运算成为了可能。由于在去年一年的......
  • C语言--枚举类型 enum
    枚举是C语言中的一种基本数据类型,用于定义一组具有离散值的常量。在我们的程序开发时,对于某个变量有很多个不同的状态,比如,一天可以是星期一或星期二,如果我们不使用枚举......
  • Rust 最大公约数
    计算两个非负整数p和q的最大公约数:若q是0,则最大公约数为p。否则,将p除以q得到余数r,p和q的最大公约数即为q和r的最大公约数。fngcd(p:u32,q:u32)......
  • 枚举
     1.循环枚举for(inta=1;a<=3;a++){ for(intb=1;b<=3;b++){ for(intc=1;c<=3;c++){ for(intd=1;d<=3;d++){ for(inte=1;e<=3;e++){ for(int......
  • 约数个数统计问题探究
    约数个数统计问题探究              衡阳市第八中学邹毅约数个数统计问题是在算法学习过程一个非常经典的问题,一般的描述为给出一个正整数N,请求出它的......
  • day03-面向对象高级3-内部类&枚举&泛型
    1,内部类回顾:之前学了类的四个成员,分别是成员变量,成员方法,代码块,构造器,现在这是第五个成员,内部类;前三个作了解,第四个重点学习。内部类的应用场景......
  • JavaSE5️⃣核心类 - 枚举(enum)
    1、枚举1.1、含义维基百科在数学和计算机科学理论中,一个集的枚举是指:列出有穷序列集的所有成员的程序。一种特定类型对象的计数。这两种类型经常重叠,是一个被命......
  • JavaScript 枚举对象中的属性
    <!DOCTYPEhtml><html> <head> <metacharset="UTF-8"> <title></title> <scripttype="text/javascript"> varobj={ name:"孙悟空", age:1......