基础数学知识·质数

初见安~本章讲一点儿数学知识最近讲的东西好像越来越基础了……

1.质数

质数——若一个正整数除了它自己和1没有别的因数了,则称这个数为质数(or素数),否则合数。

比如:3=1*3,3就是一个质数;8=1*8=2*4,8就是个合数。

在c++里我们要判断质数or筛选质数,可以运用到以下几种方法:

(1) 试除法

若一个正整数N为合数,则在2~N-1里必定可以找到N的因数M。而我们可以知道:N的合数成双出现,不成双则为√N,如9=3*3(这里算3为一个合数),所以N若为合数,则在2~√N里一定可以找到一个N的因数。因此我们可以直接用for循环除以N来验证N是否为质数。

#include<iostream>
#include<cmath>
using namespace std;
int main()
{
	int n;
	cin>>n;
	for(int i=2;i<=sqrt(n);i++)
	{
		if(n%i==0)//取余
		{
			cout<<"No"<<endl;
			return 0;//找到了一个因数,则不必继续了
		}
	}
	cout<<"Yes"<<endl;
	return 0;
}

(2)Eratosthenes算法

看起来是个很高大上的名字(我都不会读),其实也是很简单的——但这一算法比较适用于要打出2~N之内的质数or统计有多少个,也就是全局性的问题。同样基于我们对质数的定义——一个正整数,除了1和它本身没有别的因数。所以有别的因数的都不是质数。

例——输出1~N以内所有的质数。

#include<iostream>
using namespace std;
int n;
bool v[110];
int main()
{
	cin>>n;
	for(int i=2;i<=n;i++)//2~n
	{
		if(v[i]) continue;//已经标记为合数了,继续循环不做操作
		cout<<i<<" ";
		for(int j=i;j<=n/i;j++)
		{
			v[i*j]=1;//找可以被i整除的n以内的数并标记
		}
	}
	return 0;
}

这一算法的时间复杂度为O(NloglogN),效率是十分高的,也十分常用。


(3)线性筛法

Eratosthenes算法就算优化也会重复标记合数,如12会被2和3重复标记,所以我们试试线性筛法。

这一筛法运用到了一个数学结论:任何一个合数都可以被分解为几个素数的乘积。如44=2*2*11等等。

考虑到上述的重复标记问题(加一个v的判断也可以,但为了优化还是介绍一下)

【p.s】最小质因数,顾名思义就是某合数的一个最小的为质数的因数。

#include<iostream>
using namespace std;
int n;
int v[1100];//在i下标处放i的最小质因数 
int prime[1100];//存放质数 
int m=0;
int main()
{
	cin>>n;
	for(int i=2;i<=n;i++)
	{
		if(v[i]==0)//不曾被标记上最小质因数,则i为质数。 
		{
			v[i]=i;
			//它本身作为一个因数,去筛将它作为最小质因数的数 
			prime[++m]=i;
		}
		
		for(int j=1;j<=m;j++)
		{
			if(prime[j]>v[i]||prime[j]>n/i) break;
			//i有比prime[j]更小的质因数,也就是已被标记 
			v[i*prime[j]]=prime[j];//没有则继续标记 
		}
	}
	
	for(int i=1;i<=m;i++)
	{
		cout<<prime[i]<<" ";
	}
	return 0;
}

这一算法中每个合数只会被它的最小质因数标记一次,时间复杂度为O(N)。


(4)质因数分解

例题:输入一大于一的整数n,将n分解为几个质数的乘积。

由上文所提到的:每个合数都可以被分解为几个质数的乘积,同时任意一个大于1的正整数都能唯一分解为有限个质数的乘积。所以我们可以尝试一下将试除法和Eratosthenes算法结合起来——扫描2~√N中的每个数d,若d能整除N,则存起来,并统计需要多少个d相乘。这里d天然保证了为质数,因为每个合数都可以分解为几个质数的乘积,在到这个合数之前n就应当已经被除尽了。

#include<iostream>
#include<cmath>
using namespace std;
int n;
int p[1100];//从小到大存放有哪些因数 
int c[1100];//存放第m个因数需要乘的次数 
int m=0;//计数 
int main()
{
	cin>>n;
	cout<<n;//格式而已,不用在意。毕竟操作过后n变了 
	for(int i=2;i<=sqrt(n);i++)
	{
		if(n%i==0)//找到因数 
		{
			p[++m]=i; 
			c[m]=0;
			while(n%i==0)//可以分解i则继续分解 
			{
				n/=i;
				c[m]++;//统计次数 
			}
		}
	}
	if(n>1)//最后n还是无法分解完,则为质数 
	{
		p[++m]=n;c[m]=1;
	}
	
	cout<<"=";//作为一个强迫症,为了格式而已…… 
	
	int num=0;//为了格式+1 
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=c[i];j++)
		{
			if(num==0) cout<<p[i];
			else cout<<"×"<<p[i];
			num++;
		}
	}
	return 0;
}

毕竟基本上是纯数学知识,还是很好理解的~

迎评:)

——End——

猜你喜欢

转载自blog.csdn.net/qq_43326267/article/details/83097286
今日推荐